什么是Func,如何以及何时使用

什么是Func<>和它用于什么?

Func<T>是一个返回Ttypes值的方法的预定义委托types。

换句话说,你可以使用这个types来引用一个返回T值的方法。 例如

 public static string GetMessage() { return "Hello world"; } 

可能是这样引用的

 Func<string> f = GetMessage; 

把它想象成一个占位符。 如果代码遵循特定的模式,但不需要绑定到任何特定的function,则它会非常有用。

例如,请考虑Enumerable.Select扩展方法。

  • 模式是:对于序列中的每个项目,从该项目中select一些值(例如属性),并创build一个由这些值组成的新序列。
  • 占位符是:一些select器函数,实际上获得上述序列的值。

这个方法需要一个Func<T, TResult>而不是任何具体的函数。 这允许它在上述模式适用的任何上下文中使用。

所以举例来说,我有一个List<Person> ,我只想列出每个人的名字。 我可以做这个:

 var names = people.Select(p => p.Name); 

或者说我想要每个人的年龄

 var ages = people.Select(p => p.Age); 

马上,你可以看到我是如何利用两个不同函数( p => p.Namep => p.Age )代表一个模式的代码(带有Select )。

另一种方法是在每次想要扫描不同types的值的序列时写入不同版本的Select 。 所以要达到和上面一样的效果,我需要:

 // Presumably, the code inside these two methods would look almost identical; // the only difference would be the part that actually selects a value // based on a Person. var names = GetPersonNames(people); var ages = GetPersonAges(people); 

以一个代理人作为占位符,我就不必像这样一遍又一遍地写出相同的模式。

Func<T1, T2, ..., Tn, Tr>表示一个函数,它取(T1,T2,…,Tn)参数并返回Tr。

例如,如果你有一个function:

 double sqr(double x) { return x * x; } 

你可以把它保存为某种函数variables:

 Func<double, double> f1 = sqr; Func<double, double> f2 = x => x * x; 

然后像使用sqr一样使用:

 f1(2); Console.WriteLine(f2(f1(4))); 

等等

请记住,它是一个代表,更高级的信息参考文档。

Func<T1,R>和其他预定义的通用Func委托( Func<T1,T2,R>Func<T1,T2,T3,R>等)是generics委托,返回最后一个generics参数的types。

如果你有一个需要返回不同types的函数,根据参数,你可以使用一个Func委托,指定返回types。

这只是一个预定义的通用委托。 使用它你不需要声明每个代表。 还有另一个预定义的委托, Action<T, T2...> ,它是相同的,但是返回void。

当我创build一个需要个性化的组件时,我发现Func非常有用。

拿这个非常简单的例子:一个PrintListToConsole组件。

一个非常简单的对象,将这个对象列表打印到控制台。 你想让使用它的开发者个性化输出。

例如,你想让他定义一个特定types的数字格式等等。

没有Func

首先,你必须为一个类创build一个接口,接受input并产生string打印到控制台。

 interface PrindListConsoleRender<T> { String Render(T input); } 

然后,您必须创buildPrintListToConsole类,该类使用先前创build的接口并将其用于列表的每个元素。

 class PrintListToConsole<T> { private PrindListConsoleRender<T> _renderer; public void SetRenderer(PrindListConsoleRender<T> r) { // this is the poin where I can personalize the render mechanism _renderer = r; } public void PrintToConsole(List<T> list) { foreach (var item in list) { Console.Write(_renderer.Render(item)); } } } 

需要使用组件的开发人员必须:

1)实现接口

2)将真实的类传递给PrintListToConsole

 class myrenderer : PrindListConsoleRender<int> { public String Render(int input) { return "Number: " + input; } } class Program { static void Main(string[] args) { var list = new List<int> { 1, 2, 3 }; var printer = new PrintListToConsole<int>(); printer.SetRenderer(new myrenderer()); printer.PrintToConsole(list); string result = Console.ReadLine(); } } 

使用Func就简单多了

在组件内部,你定义了一个Functypes的参数,它代表一个函数的接口,它接受一个types为T的input参数并返回一个string(控制台的输出)

 class PrintListToConsole<T> { private Func<T, String> _renderFunc; public void SetRenderFunc(Func<T, String> r) { // this is the point where I can set the render mechanism _renderFunc = r; } public void StampaFunc(List<T> list) { foreach (var item in list) { Console.Write(_renderFunc(item)); } } } 

当开发人员使用你的组件时,只需传递给组件的Functypes的实现,这是一个为控制台创build输出的函数。

 class Program { static void Main(string[] args) { var list = new Array[1, 2, 3]; var printer = new PrintListToConsole<int>(); printer.SetRenderFunc((o) => "Number:" + o); string result = Console.ReadLine(); } } 

Func允许您即时定义一个通用的方法接口。 您可以定义input的types和输出的types。 简单而简洁。