有没有办法导致传递给Control.BeginInvoke的委托的类型推断?

Reg*_*dit 2 .net c# delegates winforms

Control.BeginInvoke:

在此输入图像描述

在此输入图像描述

在这两种情况下,似乎很清楚编译器具有推断委托类型所需的所有信息.然而,在这两种情况下,类型推断似乎都不起作用:

 BeginInvoke(myMethodThatTakesNoParams);
Run Code Online (Sandbox Code Playgroud)

产生编译错误

错误105'System.Windows.Forms.Control.BeginInvoke(System.Delegate)'的最佳重载方法匹配有一些无效的参数

同样如此

BeginInvoke(ShowProcessErrors, new object[] { process });
Run Code Online (Sandbox Code Playgroud)

两个方法调用只有在我将其更改为explitly创建委托并传递它时才会编译.以下两种编译都很好:

BeginInvoke(new MethodInvoker(myMethodThatTakesNoParams));
Run Code Online (Sandbox Code Playgroud)

BeginInvoke(new ProcessErrorDelegate(ShowProcessErrors), new object[] { process });
Run Code Online (Sandbox Code Playgroud)

似乎没有任何明显的理由为什么类型推断在这里不起作用.有BeginInvoke没有明确创建委托的方法来调用?

Mik*_*ray 7

问题在于它myMethodThatTakesNoParams不是真正的委托,而是编译器所谓的"方法组".方法组不是CLR中的真实类型.必须将其转换为要使用的委托类型.当您使用这样的方法组时:

Action a = myMethodThatTakesNoParams;
Run Code Online (Sandbox Code Playgroud)

编译器识别出您要将方法组转换为委托并为您插入转换.它产生的IL有效地说:

Action a = new Action(myMethodThatTakesNoParams);
Run Code Online (Sandbox Code Playgroud)

当你说:

Delegate d = myMethodThatTakesNoParams
Run Code Online (Sandbox Code Playgroud)

编译器实际上不知道该怎么做.从理论上讲,它可以为您选择任何兼容的委托类型,但C#通常不会将您未使用的类型插入表达式中.由于它不知道您希望方法组转换为什么委托,因此编译器会产生错误.

我在我的示例中使用了变量赋值,但是相同的逻辑适用于方法的参数.

解决方法是编写自己的扩展方法,其中包含特定的委托类型:

static class ControlExtensions
{
    public static IAsyncResult BeginInvoke(this Control c, Action a)
    {
        return c.BeginInvoke(a);
    }
}
Run Code Online (Sandbox Code Playgroud)