将方法组隐式转换为委托(对于 Control.Invoke 的参数)

Implicitly convert method group to Delegate (for argument of Control.Invoke)

我正在开发 Windows Forms 应用程序,它包含自定义控件,其方法可能会从 UI 线程以外的线程调用。所以这些方法因此看起来有点像这样以防止异常:

public void DoSomeStuff()
{
    if (InvokeRequired)
    {
        Invoke((Action)DoSomeStuff);
    }
    else
    {
        // Actually do some stuff.
    }
}

方法组 DoSomeStuffAction 的显式转换引起了我的注意,因此我比以前更深入地研究了委托和其他相关主题。

虽然我在这里看到了一些相关问题,但我一直无法找到我的确切答案,即:

在这种情况下,为什么方法组 DoSomeStuff 需要显式转换为 Action

如果删除强制转换,则会出现两个错误:

Error 102 Argument 1: cannot convert from 'method group' to 'System.Delegate'

Error 101 The best overloaded method match for 'System.Windows.Forms.Control.Invoke(System.Delegate, params object[])' has some invalid arguments

编译器显然对使用 Invoke 的哪个重载感到困惑这一事实似乎是一个很大的提示,但我仍然不确定为什么它无法弄清楚这一点。我希望编译器推断出 Invoke 的第一个重载,它采用单个 Delegate 参数,是应该使用的

我希望是这样,因为如果代码这样写就没有问题:

Action a = DoSomeStuff;
Invoke(a);

方法组 DoSomeStuff 可以隐式转换为 Action 委托类型,并且 ActionSystem.Delegate 派生(技术上?),所以 Invoke 可以毫无问题地处理参数 a 。但是为什么当我试图直接将 DoSomeStuff 作为参数传递时,编译器不能完成隐式转换呢?老实说,我不相信我自己的逻辑,但我仍然不确定我错过了什么。

问题不在于编译器无法选择重载。 "best match" 重载是您想要的重载,但它的参数无效。 C# 语言没有定义任何从方法组 (DoSomeStuff) 到 System.Delegate.

的隐式转换

您可能会说编译器应该只选择 Action/Func 类型中的一种,这已被要求作为语言功能。现在这不是 C# 的一部分。 (我不知道为什么;我希望语言请求通过。)

System.Windows.Forms.Control.Invoke 是在 .NET 1.0 中创建的。今天,人们会使用以下签名:

void Invoke(Action action);
Task InvokeAsync(Action action);

而且它会很简单。

尝试迁移到 await,这不再是一个问题。

使用 C# 10 和 Visual Studio 2022,您不再需要显式转换(自然函数类型)。