匿名函数转换

Anonymous function conversion

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

...

Specifically, an anonymous function F is compatible with a delegate type D provided:

...

If F does not contain an anonymous-function-signature, then D may have zero or more parameters of any type, as long as no parameter of D has the out parameter modifier.

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

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();
        }
   }
}

上面的代码哪里出错了?

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

您指出的 6.5 美元规格还说:

The expression does not have a type but can be implicitly converted to a compatible delegate type or expression tree type

和 $6.5.1:

Conversion of an anonymous function to a delegate type produces a delegate instance which references the anonymous function

匿名方法只能用lambda表达式定义, 实际上,这些东西是不同的。

Lambda expression has no type and can be implicity converted to Expression, used in LINQ query expression and Anonymous 方法定义。

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

引用您提供的规范

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

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

"If F does not contain an anonymous-function-signature" 表示 签名缺失 ,但 lambda 的 '()'表示 不接受任何参数的签名 。正如@Johnny 的回答中提到的那样,lambda 不能在没有签名的情况下声明。关于委托示例:查看代码示例中的第 4 个示例 - 它无效,因为具有不接受任何参数的不兼容签名,第 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);
}

A delegate is a type that represents references to methods with a particular parameter list and return type

原则上一切都从delegate开始,它表示特定参数列表return类型

If F does not contain an anonymous-function-signature, then D may have zero or more parameters of any type, as long as no parameter of D has the out parameter modifier.

可以使用语法 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) => { 语句列表 }