Create a C# Func<> type alias
Asked Answered
H

1

11

I'm working on a library that has several places where a user can inject a lambda function to customize a complex background process. They are essentially making small modifications to how the library works. The library is handling dynamic types, built at compile or at run-time, so there are no concrete classes to which I can add abstract or virtual members. The library could be handling dozens of client-defined configurations with from a few to a large number of lambda customizations (each customization is attached to one of the dynamically-defined structures the client is building, and passing to the library).

The signature of a lambda function can be a little complicated, something like this:

Func<SourceList, PredList, Dictionaries, object>

Now, what I find myself doing is repeating this complicated Func<> in both the public and private interfaces and variables. Something like:

private readonly IList<Func<SourceList, PredList, Dictionaries, object>> _processFunctions
            = new List<Func<SourceList, PredList, Dictionaries, object>>();

public void AddProcessFunction(Func<SourceList, PredList, Dictionaries, object> processFunction)
{
    _processFunctions.Add(processFunction);
}

The user will do this:

someObject.AddProcessFunction((fromList, predList, dict) => { some process impl }
someOtherObj.AddTargettedProcessFunction("Account", 
                                         (fromList, predList, dict) => { some process impl }
...

If I have to make a change to the signature of the lambda, I have to modify this in many places. I was hoping there was a way to define a type that I could use to store this signature in one place. I did find that I can do this:

using ProcessFunc = System.Func<SourceList, PredList, Dictionaries, object>;

...

private readonly IList<ProcessFunc> _processFunctions = new List<ProcessFunc>();
public void AddProcessFunction(ProcessFunc processFunction)
{
    _processFunctions.Add(processFunction);
}

This does what I want, but this isn't a great solution as it has to be repeated in every .cs file in the library in exactly the same way (or, conversely, it could have a completely different alias name in every file, and still work just fine, since this is essentially a macro replacement).

While this method cleans up the code quite a bit, and does reduce the duplication of the Func<> definition, the full Func<> definition is still repeated over and over in the the generated library documentation, since the full definition is repeated on the method signature. This makes it very hard for a reader of the documentation to see which functions take the same lambda as they have to compare multiple complex parameters, they will never see ProcessFuncTypeA or ProcessFuncTypeB, so two lambdas that are similar but different are harder to distinguish visually (of course I would use good names for the different signatures).

What I was hoping for was something like this:

public Function ProcessFunc : Func<SourceList, PredList, Dictionaries, object>;

Is there a better way (or even another way) to define a Func<> type in one place and reuse it in multiple places in the library? Am I missing something obvious?

Thanks!

Herl answered 20/12, 2017 at 1:3 Comment(1)
Look up delegate :)Langlauf
C
21

The C# Reference Source can sometimes provide helpful hints on how internals are implemented, and how you can implement similar things.

So, the generic Func<> with 3 arguments is defined as

public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);

Thus you can define your specific Func<> variation as

public delegate object ProcessFunc(SourceList arg1, PredList arg2, Dictionaries arg3);
Cribbing answered 20/12, 2017 at 1:8 Comment(1)
That is exactly what I needed. I knew I was overlooking something. Thanks!Herl

© 2022 - 2024 — McMap. All rights reserved.