Dan*_*Tao 84
Think of it as a placeholder. It can be quite useful when you have code that follows a certain pattern but need not be tied to any particular functionality.
例如,考虑Enumerable.Select
扩展方法.
这种方法Func<T, TResult>
取代了任何具体的功能.这允许它在上述模式适用的任何环境中使用.
例如,假设我有一个List<Person>
,我只想要列表中每个人的名字.我可以做这个:
var names = people.Select(p => p.Name);
Run Code Online (Sandbox Code Playgroud)
或者说我想要每个人的年龄:
var ages = people.Select(p => p.Age);
Run Code Online (Sandbox Code Playgroud)
马上,您可以看到我如何能够利用代表模式(with )的相同代码和两个不同的函数(和).Select
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);
Run Code Online (Sandbox Code Playgroud)
在代理人担任占位符的情况下,我不必在这种情况下反复写出相同的模式.
Bri*_*sen 71
Func<T>
是一个返回某种类型值的方法的预定义委托类型T
.
换句话说,您可以使用此类型来引用返回某些值的方法T
.例如
public static string GetMessage() { return "Hello world"; }
Run Code Online (Sandbox Code Playgroud)
可以这样引用
Func<string> f = GetMessage;
Run Code Online (Sandbox Code Playgroud)
Gro*_*ozz 62
Func<T1, T2, ..., Tn, Tr>
表示一个函数,它接受(T1,T2,...,Tn)参数并返回Tr.
例如,如果您有一个功能:
double sqr(double x) { return x * x; }
Run Code Online (Sandbox Code Playgroud)
您可以将其保存为某种函数变量:
Func<double, double> f1 = sqr;
Func<double, double> f2 = x => x * x;
Run Code Online (Sandbox Code Playgroud)
然后完全按照使用sqr的方式使用:
f1(2);
Console.WriteLine(f2(f1(4)));
Run Code Online (Sandbox Code Playgroud)
等等
但请记住,它是一个委托,更高级的信息请参考文档.
Ode*_*ded 11
Func<T1,R>
和其他预定义的通用Func
名代表(Func<T1,T2,R>
,Func<T1,T2,T3,R>
和其他人)是返回的最后一个泛型参数的类型,泛型委托.
如果您有一个需要返回不同类型的函数,则根据参数,您可以使用Func
委托,指定返回类型.
Mar*_*oli 11
Func<T>
当我创建一个需要"动态"个性化的组件时,我觉得非常有用.
举一个非常简单的例子:一个PrintListToConsole<T>
组件.
一个非常简单的对象,将此对象列表打印到控制台.您希望让使用它的开发人员个性化输出.
例如,您想让他定义特定类型的数字格式等.
没有Func
首先,您必须为获取输入的类创建一个接口,并生成要打印到控制台的字符串.
interface PrintListConsoleRender<T> {
String Render(T input);
}
Run Code Online (Sandbox Code Playgroud)
然后,您必须创建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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
需要使用您的组件的开发人员必须:
实现界面
把真正的课传给了 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();
}
}
Run Code Online (Sandbox Code Playgroud)使用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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
当开发人员使用您的组件时,他只需将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();
}
}
Run Code Online (Sandbox Code Playgroud)
Func<T>
允许您动态定义通用方法接口.
您可以定义输入的类型以及输出的类型.简洁明了.