创建一个C#Func<>类型别名

时间:2017-12-20 01:03:42

标签: c# lambda delegates

我正在开发一个库,它有几个用户可以注入lambda函数来自定义复杂后台进程的地方。它们实质上是对库的工作方式进行了少量修改。该库正在处理在编译或运行时构建的动态类型,因此没有具体的类可以添加抽象或虚拟成员。该库可以处理许多客户端定义的配置,从几个到大量的lambda自定义(每个自定义都附加到客户端正在构建的动态定义的结构之一,并传递给库)。

lambda函数的签名可能有点复杂,如下所示:

Func<SourceList, PredList, Dictionaries, object>

现在,我发现自己正在做的是重复这个复杂的Func&lt;&gt;在公共和私有接口和变量中。类似的东西:

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);
}

用户将执行此操作:

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

如果我必须更改lambda的签名,我必须在很多地方修改它。我希望有一种方法可以定义一种类型,我可以用它来将这个签名存储在一个地方。我确实发现我可以这样做:

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

...

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

这就是我想要的,但这不是一个很好的解决方案,因为它必须以完全相同的方式在库中的每个.cs文件中重复(或者相反,它可能具有完全不同的别名。每个文件,仍然可以正常工作,因为这实际上是一个宏替换。)

虽然这种方法可以清除相当多的代码,但确实减少了Func&lt;&gt;的复制。定义,完整的Func&lt;&gt;由于在方法签名上重复了完整定义,因此仍然会在生成的库文档中反复重复定义。这使得文档的读者很难看到哪些函数采用相同的lambda来比较多个复杂参数,它们永远不会看到ProcessFuncTypeA或ProcessFuncTypeB,因此两个相似但不同的lambda更难以在视觉上区分(当然我会为不同的签名使用好名字。)

我所希望的是这样的:

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

是否有更好的方法(甚至是其他方式)来定义Func&lt;&gt;在一个地方输入并在图书馆的多个地方重复使用?我错过了一些明显的东西吗?

谢谢!

1 个答案:

答案 0 :(得分:11)

C# Reference Source有时可以提供有关内部实现方式的有用提示,以及如何实现类似的内容。

因此,具有3个参数的通用Func<>被定义为

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

因此,您可以将特定Func<>变体定义为

public delegate object ProcessFunc(SourceList arg1, PredList arg2, Dictionaries arg3);