MethodInvoker + lambda +参数+交叉线程操作

本文关键字:线程 操作 参数 lambda MethodInvoker | 更新日期: 2023-09-27 17:53:11

我用这个来改变其他线程的一些东西:

        MethodInvoker m = () => { login_submit.Text = "Login"; };
        if (InvokeRequired)
        {
            BeginInvoke(m);
        }
        else
        {
            Invoke(m);
        }

运行正常

如何将参数传递给lambda表达式?

我想做这样的事情:

        MethodInvoker m = (string txt) => { login_submit.Text = txt; };
        if (InvokeRequired)
        {
            BeginInvoke(m); // I need to pass txt string in some way here.
        }
        else
        {
            Invoke(m); // I need to pass txt string in some way here.
        }

MethodInvoker + lambda +参数+交叉线程操作

如果这是您的常见场景,我建议编写一个扩展方法:

public static class ControlExtensions
{
  public static void EnsureInvokeAsync(this Control control, Action action)
  {
     if (control.InvokeRequired) control.BeginInvoke(action);
     else action();
  }
}
class MyControl : UserControl
{
    void M(string s)
    {
       // the lambda will capture the string in a closure
       // the compiler does all the hard work for you
       this.EnsureInvokeAsync(() => _button.Text = s);
    }
}

此外,您应该考虑使用BackgroundWorker或任务进行异步操作。

如果invokerequirequired为false,那么您根本不需要担心调用任何东西-您已经在正确的线程上了。

一个更好的解决方案可能是这样的:

public delegate void InvokerDelegate(string data);
public void DoStuff(string data){
  login_submit.Text = data;
}

,然后调用时do:

if (InvokeRequired){
  Invoke(InvokerDelegate(DoStuff), "something");
}
else{
  DoStuff("Something");
}

您将看到的一个相当常见的模式是对在多线程环境中操作GUI的函数做这样的操作

public delegate void InvokerDelegate();
public void DoGuiStuff(){
  if (login_submit.InvokeRequired){
    login_submit.Invoke(InvokerDelegate(DoGuiStuff));
    return;  
  }
  login_submit.Text = "Some value";
}

如果使用上面的模式,函数检查是否需要调用,如果需要,则在正确的线程上调用自己。然后返回。当它调用自己时,检查是否需要调用返回false,因此它不需要再次调用自己-它只是运行代码。

编辑:我只是回到winforms,并试图使用这种模式,只是花了几个令人沮丧的分钟试图找出为什么我不能调用lambda。我想我最好回来更新这个答案,以添加所需的转换,以防其他人试图使用它。

MethodInvoker是一个没有任何参数的委托类型。如果我理解正确的话,你可以这样做:

string txt = "some text";
MethodInvoker m = () => { login_submit.Text = txt; };

可以使用闭包将值传递到lambda的主体中。

string value = "Login";
MethodInvoker m = () => { login_submit.Text = value; };
if (InvokeRequired)
{
    BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
    Invoke(m); // I need to pass txt string in some way here.
}

或者可以使用类成员的数据