C# Invoke 调用中的匿名方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/253138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 20:03:57  来源:igfitidea点击:

Anonymous method in Invoke call

c#.netcompiler-errorsanonymous-methods

提问by Duncan

Having a bit of trouble with the syntax where we want to call a delegate anonymously within a Control.Invoke.

我们想在 Control.Invoke 中匿名调用委托的语法有点麻烦。

We have tried a number of different approaches, all to no avail.

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

For example:

例如:

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

where someParameter is local to this method

其中 someParameter 是此方法的本地参数

The above will result in a compiler error:

以上将导致编译器错误:

Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type

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

采纳答案by Marc Gravell

Because Invoke/BeginInvokeaccepts Delegate(rather than a typed delegate), you need to tell the compiler what type of delegate to create ; MethodInvoker(2.0) or Action(3.5) are common choices (note they have the same signature); like so:

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

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

If you need to pass in parameters, then "captured variables" are the way:

如果需要传入参数,那么“捕获的变量”是这样的:

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

(caveat: you need to be a bit cautious if using captures async, but syncis fine - i.e. the above is fine)

(警告:如果使用捕获async,你需要有点谨慎,但同步很好 - 即上面的很好)

Another option is to write an extension method:

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

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

then:

然后:

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

You can of course do the same with BeginInvoke:

你当然可以做同样的事情BeginInvoke

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

If you can't use C# 3.0, you could do the same with a regular instance method, presumably in a Formbase-class.

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

回答by Fran?ois

myControl.Invoke(new MethodInvoker(delegate() {...}))

回答by Jelon

You need to create a delegate type. The keyword 'delegate' in the anonymous method creation is a bit misleading. You are not creating an anonymous delegate but an anonymous method. The method you created can be used in a delegate. Like this:

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

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

回答by Vokinneberg

Actually you do not need to use delegate keyword. Just pass lambda as parameter:

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

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

回答by Rory

I had problems with the other suggestions because I want to sometimes return values from my methods. If you try to use MethodInvoker with return values it doesn't seem to like it. So the solution I use is like this (very happy to hear a way to make this more succinct - I'm using c#.net 2.0):

我对其他建议有问题,因为我有时想从我的方法中返回值。如果您尝试将 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;
        }));
    }

回答by mhamrah

For the sake of completeness, this can also be accomplished via an Action method/anonymous method combination:

为了完整起见,这也可以通过 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();
});

回答by Jürgen Steinblock

I never understood why this makes a difference for the compiler, but this is sufficient.

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

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

Bonus: add some error handling, because it is likely that, if you are using Control.Invokefrom a background thread you are updating the text / progress / enabled state of a control and don't care if the control is already disposed.

奖励:添加一些错误处理,因为很可能,如果您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 Du D.

I like to use Action in place of MethodInvoker, it is shorter and looks cleaner.

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

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

// OR

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

Eg.

例如。

// 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";
}