调用调用中的匿名方法


131

在想要在Control.Invoke中匿名调用委托的语法上有麻烦。

我们尝试了许多不同的方法,但都无济于事。

例如:

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

其中someParameter在此方法本地

以上将导致编译器错误:

无法将匿名方法转换为类型“ System.Delegate”,因为它不是委托类型

Answers:


221

因为Invoke/ BeginInvoke接受Delegate(而不是类型化的委托),所以您需要告诉编译器要创建什么类型的委托;MethodInvoker(2.0)或Action(3.5)是常见选择(请注意,它们具有相同的签名);像这样:

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});

如果需要传递参数,则可以使用“捕获的变量”:

string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});

(注意:如果使用captures async,则需要谨慎一点,但是sync很好-即上述情况很好)

另一种选择是编写扩展方法:

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate)action);
}

然后:

this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });

您当然可以使用以下方法进行操作BeginInvoke

public static void BeginInvoke(this Control control, Action action)
{
    control.BeginInvoke((Delegate)action);
}

如果您不能使用C#3.0,则可以使用常规实例方法(大概是在Form基类中)执行相同的操作。


如何在此答案中将参数传递给您的第一个解决方案?我的意思是这个解决方案:control.Invoke((MethodInvoker)委托{this.Text =“ Hi”;});
uzay95,2009年

1
为什么在无需对Action进行显式强制转换的情况下调用扩展方法?
P.Brian.Mackey 2013年

因为编译器可以从用法中推断出来。
RoboJ1M '16

1
就像能Form.Load += Loader()代替旧的一样Form.Load += new EventHandler(Loader())
RoboJ1M 2016年

49

实际上,您不需要使用委托关键字。只需将lambda作为参数传递:

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));


13

您需要创建一个委托类型。匿名方法创建中的关键字“ delegate”有点误导。您不是在创建匿名委托,而是在创建匿名方法。您创建的方法可以在委托中使用。像这样:

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));

8

为了完整起见,这也可以通过Action方法/匿名方法的组合来完成:

//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
  SomeFunc();
  SomeOtherFunc();
});

Invoke((Action) Process);是最好的答案,谢谢!
金吉诺夫

5

我对其他建议有疑问,因为我有时想从我的方法中返回值。如果您尝试将MethodInvoker与返回值一起使用,则似乎不喜欢它。因此,我使用的解决方案是这样的(非常高兴听到一种使代码更简洁的方法-我正在使用c#.net 2.0):

    // Create delegates for the different return types needed.
    private delegate void VoidDelegate();
    private delegate Boolean ReturnBooleanDelegate();
    private delegate Hashtable ReturnHashtableDelegate();

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required

    // Here a case where there's no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

    // Here's an example of a value being returned
    public Hashtable CurrentlyLoadedDocs()
    {
        return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
        {
            return myWindow.CurrentlyLoadedDocs;
        }));
    }

1

我喜欢用Action代替MethodInvoker,它更短并且看起来更干净。

Invoke((Action)(() => {
    DoSomething();
}));

// OR

Invoke((Action)delegate {
    DoSomething();
});

例如。

// Thread-safe update on a form control
public void DisplayResult(string text){
    if (txtResult.InvokeRequired){
        txtResult.Invoke((Action)delegate {
            DisplayResult(text);
        });
        return;
    }

    txtResult.Text += text + "\r\n";
}

0

我从来不明白为什么这会对编译器产生影响,但这足够了。

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        control.Invoke(action);
    }
}

奖励:添加一些错误处理,因为如果Control.Invoke从后台线程使用该控件,则可能会更新控件的文本/进度/启用状态,而不必关心控件是否已被处置。

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.