“delegate {}”匹配“Func <int,int,..>”?</int,int,..>

时间:2012-11-10 20:48:28

标签: c# .net generics .net-4.0

我正在阅读Jon Skeet的回答here

他的一个样本是:

  static void Main()
    {
        int x = 0;
        Foo( delegate { return x; } );
    }

    static void Foo(Func<int, int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }

但是Foo(Func<int, int>)如何处理delegate { return x; } Func<int>

事实上,Func< int,int,int,int,...>也可以处理delegate { return x; } ...

问题1 对此行为有任何解释吗?

问题2

我有这段代码:

class MyClass
{
    public delegate void MyEventHandler(object sender);
    public  event MyEventHandler MyEvent;
}

我想使用通用处理程序:

class MyClass
{
    public  Action<object> MyEventHandler;
    public  event MyEventHandler MyEvent;
}

但是我收到了这个错误:

  

'UserQuery.MyClass.MyEventHandler(object)'是'方法',但用作'类型'

为什么不识别它?

1 个答案:

答案 0 :(得分:8)

第一个问题的答案是代理的参数是由编译器推断的。编译一个匿名方法,该方法将int作为参数,并且不执行任何操作。代码可以这样写:

Foo( delegate (int dummy) { return x; } );

通过省略参数列表,您告诉编译器发出一个方法,该方法与当前上下文中的委托类型具有相同的参数类型。编译器知道期望Func<int, int>,因此它能够使匿名方法的参数类型匹配。

换句话说,delegate { ... }告诉编译器“创建一个匿名方法,但我不关心参数是什么,因为我不打算使用它们,所以发出任何参数将允许这个委托在这种情况下是可以接受的。“ (这与delegate () { ... }不同,这意味着“创建一个接受零参数的匿名方法。”注意括号。如果将这些括号添加到示例代码中,它确实无法编译。)

在第二种情况下,您使用的是需要类型名称的字段名称。定义字段不会创建具有字段名称的类型。你的第一个例子是正确的;在这种情况下,MyEventHandler是一种类型,而不是一个字段。 (即使这确实有效,使用泛型也不会有用,因为最终的委托签名已在编译时确定。使用泛型不会带来任何净优势。)