什么是Func<>
以及它用于什么?
答案 0 :(得分:78)
将其视为占位符。当您的代码遵循某种模式但不需要与任何特定功能相关联时,它会非常有用。
例如,请考虑Enumerable.Select
扩展方法。
此方法采用Func<T, TResult>
而不是任何具体函数。这允许它在适用上述模式的任何上下文中使用。
例如,假设我有一个List<Person>
,我只想要列表中每个人的名字。我可以这样做:
var names = people.Select(p => p.Name);
或者说我想要每个人的年龄:
var ages = people.Select(p => p.Age);
马上,你可以看到我如何能够利用代表模式的相同的代码(带有Select
)和两个不同< / em> functions(p => p.Name
和p => p.Age
)。
另一种方法是每次想要扫描序列以获得不同类型的值时,编写不同版本的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);
在代理人担任占位符的情况下,我不必在这种情况下反复写出相同的模式。
答案 1 :(得分:68)
Func<T>
是一个预定义的委托类型,用于返回某些T
类型值的方法。
换句话说,您可以使用此类型引用返回某些值T
的方法。 E.g。
public static string GetMessage() { return "Hello world"; }
可以像这样引用
Func<string> f = GetMessage;
答案 2 :(得分:60)
Func<T1, T2, ..., Tn, Tr>
表示一个函数,它接受(T1,T2,...,Tn)参数并返回Tr。
例如,如果你有一个功能:
double sqr(double x) { return x * x; }
您可以将其保存为某种函数变量:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
然后完全按照使用sqr:
的方式使用f1(2);
Console.WriteLine(f2(f1(4)));
等
请记住,它是一个委托,更高级的信息请参考文档。
答案 3 :(得分:11)
Func<T1,R>
和其他预定义的通用Func
委托(Func<T1,T2,R>
,Func<T1,T2,T3,R>
和其他人)是返回最后一个通用参数类型的通用委托。
如果你有一个需要返回不同类型的函数,根据参数,你可以使用Func
委托,指定返回类型。
答案 4 :(得分:10)
当我创建一个需要个性化的组件时,我发现Func<T>
非常有用&#34;即时#34;
举一个非常简单的例子:PrintListToConsole<T>
组件。
一个非常简单的对象,它将此对象列表打印到控制台。 您希望让使用它的开发人员个性化输出。
例如,您想让他定义特定类型的数字格式等等。
没有Func
首先,您必须为获取输入的类创建一个接口,并生成要打印到控制台的字符串。
interface PrintListConsoleRender<T> {
String Render(T input);
}
然后你必须创建一个类PrintListToConsole<T>
,它接受先前创建的接口,并在列表的每个元素上使用它。
class PrintListToConsole<T> {
private PrintListConsoleRender<T> _renderer;
public void SetRenderer(PrintListConsoleRender<T> r) {
// this is the point 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));
}
}
}
需要使用您的组件的开发人员必须:
实施界面
将真实班级传递给PrintListToConsole
class MyRenderer : PrintListConsoleRender<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它更简单
在组件内部,您定义了Func<T,String>
类型的参数,表示函数的接口,它接受类型为T的输入参数并返回一个字符串(控制台的输出)
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 Print(List<T> list) {
foreach (var item in list) {
Console.Write(_renderFunc(item));
}
}
}
当开发人员使用你的组件时,他只是将Func<T, String>
类型的实现传递给组件,这是一个为控制台创建输出的函数。
class Program {
static void Main(string[] args) {
var list = new List<int> { 1, 2, 3 }; // should be a list as the method signature expects
var printer = new PrintListToConsole<int>();
printer.SetRenderFunc((o) => "Number:" + o);
printer.Print(list);
string result = Console.ReadLine();
}
}
Func<T>
可让您动态定义通用方法界面。
您可以定义输入的类型以及输出的类型。
简洁明了。
答案 5 :(得分:6)
它只是一个预定义的通用委托。使用它,您不需要声明每个委托。还有另一个预定义的委托Action<T, T2...>
,它是相同的,但返回void。
答案 6 :(得分:0)
C#和Java都没有普通函数,只有成员函数(也称为方法)。而且这些方法不是一流的公民。一流的功能使我们能够创建漂亮而强大的代码,如F#或Clojure语言所示。 (例如,一等函数可以作为参数传递并可以返回函数。)Java和C#通过接口/代理对此有所改善。
Func<int, int, int> randInt = (n1, n2) => new Random().Next(n1, n2);
因此,Func
是一个内置委托,它带来了一些功能性的编程功能并有助于减少代码的冗长性。
答案 7 :(得分:-1)
也许添加一些信息还为时不晚。
总和:
Func是在系统名称空间中定义的自定义委托,它允许您使用0到16个输入参数指向具有相同签名的方法(与委托一样),并且必须返回某些内容。
命名和使用方式:
Func<input_1, input_2, ..., input1_6, output> funcDelegate = someMethod;
定义:
public delegate TResult Func<in T, out TResult>(T arg);
使用位置:
它用于lambda表达式和匿名方法。