匿名函数转换

时间:2019-01-29 05:45:59

标签: c# delegates anonymous-function

C#语言规范 6.5匿名函数转换指出:

  

...

     

具体来说,匿名函数F与提供的委托类型D兼容:

     

...

     

如果F不包含 anonymous-function-signature ,则D可能具有   零个或多个任何类型的参数,只要D的参数没有   out参数修饰符。

但是,以下代码会产生错误。

using System;
namespace DelegateAnonymousFunctionExample
{
    public delegate void D(int i, int b);
    class Program
    {
        static void Main(string[] args)
        {
            // Valid
            D f1 = (int a, int b) =>
            {
                Console.WriteLine("Delegate invoked...");
            };
            f1(3, 4);

            // Error
            D f2 = () =>
            {
                Console.WriteLine("Delegate invoked...");
            };

            Console.ReadKey();
        }
   }
}

以上代码在哪里出错?

3 个答案:

答案 0 :(得分:2)

f2变量未收到有效的方法签名,您委托D正在等待2个参数。

答案 1 :(得分:1)

  

委托是一种类型,它表示对具有特定参数列表和返回类型的方法的引用

原则上,所有内容都从delegate开始,并表示特定参数列表返回类型

  

如果F不包含匿名函数签名,则D可能具有   零个或多个任何类型的参数,只要D的参数没有   out参数修饰符。

可以使用语法delegate parameter-list { statement-list }声明匿名方法。在这种情况下,您可以在上面省略 parameter-list 的情况。另一方面,如果您提供参数,则参数类型必须完全匹配。

public delegate void MyDelegate(int a);

MyDelegate d = delegate { }; //valid
MyDelegate d = delegate(int a) { }; //valid
MyDelegate d = delegate(int a, int b) { }; //invalid

public delegate void MyDelegateOut(int a, out int b);
MyDelegateOut d = delegate { }; //invalid

如果您想使用lambda声明delegate,则无法存储省略效果,因为语法为( input-parameters => { 语句列表 }

答案 2 :(得分:0)

您指出的

6.5美元的价格规格还说:

  

表达式没有类型,但可以隐式转换为   兼容的委托类型或表达式树类型

和$ 6.5.1:

  

将匿名函数转换为委托类型会产生一个   引用匿名函数的委托实例

可以使用lambda-expression定义匿名方法, 实际上,这些事情是不同的。

Lambda expression没有类型,可以隐式转换为Expression查询表达式和LINQ方法定义中使用的Anonymous

因此,在您的错误情况下,lambda表达式将转换为不接受参数的不兼容的委托实例

您提供的规格中的报价

D f5 = delegate { Console.WriteLine("Delegate invoked..."); };

它之所以有效,是因为没有指向签名,它将被自动编译为接受(int,int)的兼容委托实例。

“如果F不包含匿名函数签名” 表示缺少签名,但是lambda的'()'表示不接受参数的签名。正如@Johnny的答案中提到的那样,lambda不能没有签名就被声明。关于代表示例:请看代码示例中的第4个示例-该示例无效,因为具有不兼容的签名(不接受args),第5个示例没有签名并且有效。

您还可以在下面复制示例并检查其编译方式(请先注释无效的代码) https://sharplab.io/

public delegate void D(int i, int b);

public void Main(string[] args) 
{        
    //valid, lambda expression will be converted to compatible delegate instance
    D f1 = (int a, int b) => Console.WriteLine("Delegate invoked...");
    f1(3, 4);

    //INVALID, lambda expression will be converted to incompatible delegate instance
    D f2 = () => Console.WriteLine("Delegate invoked...");
    f2(3, 4);

    //valid, assigning delegate with compatible signature
    D f3 = delegate(int i, int j) { Console.WriteLine("Delegate invoked..."); };
    f3(3, 4);

    //INVALID, assigning delegate with incompatible signature
    D f4 = delegate() { Console.WriteLine("Delegate invoked..."); };
    f4(3, 4);

    //valid, it will be automatically compiled to compatible delegate instance which accepts (int, int)
    D f5 = delegate { Console.WriteLine("Delegate invoked..."); };
    f5(3, 4);
}