繁体   English   中英

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

[英]Is there a way to cause type inference of the delegate passed to Control.BeginInvoke?

Control.BeginInvoke

在此输入图像描述

在此输入图像描述

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

 BeginInvoke(myMethodThatTakesNoParams);

产生编译错误

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

同样如此

BeginInvoke(ShowProcessErrors, new object[] { process });

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

BeginInvoke(new MethodInvoker(myMethodThatTakesNoParams));

BeginInvoke(new ProcessErrorDelegate(ShowProcessErrors), new object[] { process });

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

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

Action a = myMethodThatTakesNoParams;

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

Action a = new Action(myMethodThatTakesNoParams);

当你说:

Delegate d = myMethodThatTakesNoParams

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

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

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

static class ControlExtensions
{
    public static IAsyncResult BeginInvoke(this Control c, Action a)
    {
        return c.BeginInvoke(a);
    }
}

这通常是.NET程序员的一个惊喜,第15.1节中的C#语言特定说明:

请注意,System.Delegate本身不是委托类型; 它是一个类类型,从中派生所有委托类型

当然,没有方法转换为类。 BeginInvoke()的第一个参数必须是委托类型,以保持编译器满意。 也许这听起来像是一个任意的限制,绝对不是。 代表们非常重要的一点是他们是类型安全的 在像C#这样的静态类型语言中,这是一个非常重要的事情。 您不能使用太少的参数或太多的参数或错误类型的参数来调用委托。 检查代理何时创建,当您仍然穿着睡衣或舒适的隔间时,会出现编译时错误。 在运行时没有任何意外,您的程序突然在当天最不合时宜的时间内发挥作用。 此类型检查当然不适用于Delegate。 所以它不是委托类型。

确实与Control.BeginInvoke()有关,它使用后门来获取调用的方法。 Math.Pi当您传递Math.Pi而不是进度时 ,在运行代码之前无法找到。 这不是一个令人愉快的例外,因为不清楚是否你的BeginInvoke()调用错误或者被调用的方法是否引发异常。 实际上Invoke()的问题更多。

Anyhoo,必须给编译器一个委托,不止一种方法:

古老的匿名方法语法在这种情况下仍然可以很好地工作:

  this.BeginInvoke(delegate() { ShowProcessErrors(process); });

你已经找到了MethodInvoker,我通常会选择Action,因为它更短:

  this.BeginInvoke(new Action(() => ShowProcessErrors(process)));

当然,你总是可以通过扩展方法让编译器满意:

  this.BeginInvoke(() => ShowProcessErrors(process));

有:

static class Extensions {
    public static void BeginInvoke(this Control ctl, Action a) {
        ctl.BeginInvoke(a);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM