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

时间:2010-09-02 07:45:45

标签: c# .net delegates

什么是Func<>以及它用于什么?

8 个答案:

答案 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.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);

在代理人担任占位符的情况下,我不必在这种情况下反复写出相同的模式。

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

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

  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();   
        }   
    }
    
  3. 使用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表达式和匿名方法。