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 )的相同代码和两个不同的函数(和).Selectp => p.Namep => 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)

  • 不,我是对的.`static int OneArgFunc(this string i){return 42; ```Func <int> f ="foo".OneArgFunc;`.=) (4认同)
  • 这是一种特殊的扩展方法。 (3认同)
  • @Ark-kun不,那不对.`Func <T>`的定义是`委托TResult Func <out TResult>()`.没有争论.`Func <T1,T2>`将是一个带有一个参数的函数. (2认同)

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)

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

  1. 实现界面

  2. 把真正的课传给了 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>允许您动态定义通用方法接口. 您可以定义输入的类型以及输出的类型.简洁明了.

  • 感谢您发布此 Marco。它真的帮助了我。我一直试图理解 func 并在我的编程中积极使用它。此示例将清除路径。我不得不添加 StampaFunc 方法,因为它在原始代码中被遗漏了,这阻止了它的显示。 (2认同)

Ste*_*ger 6

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