【问题标题】:MethodInvoker + lambda + arguments + CrossThread OperationMethodInvoker + lambda + arguments + CrossThread 操作
【发布时间】:2011-04-24 13:09:10
【问题描述】:

我正在使用它来更改其他线程上的某些内容:

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

这工作正常。

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

我想那样做:

        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.
        }

【问题讨论】:

  • @Cody,我认为它是“某物”的缩写。

标签: c# .net multithreading invoke


【解决方案1】:

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

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 或任务进行异步操作。

【讨论】:

  • 您的回答很棒。但是因为已经接受的答案有更多细节,所以我现在不会更改接受的分析器。但我爱它。为我从来没有考虑过而感到羞耻。
【解决方案2】:

如果 InvokeRequired 为 false,那么您根本无需担心调用任何内容 - 您已经在正确的线程上。

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

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

然后当调用它时:

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 的原因。我想我最好回来更新这个答案以添加所需的演员表,以防其他人尝试使用它。

【讨论】:

  • 公共无效委托InvokerDelegate(字符串数据);给我一个“无效的令牌委托”错误。
  • Invoke(InvokerDelegate(DoStuff), "something");给我一个“当前上下文中不存在 InvokerDelegate”错误
  • 应该是 public delegate void InvokerDelegate(string data); (delegate 和 void 关键字是向后的)
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    您可以使用闭包将值传递到 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.
    }
    

    或者你可以使用班级成员的数据

    【讨论】:

    • 我不明白这个。 'login_submit.Text = value; '传递什么?这不就是执行内联代码吗?
    猜你喜欢
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 2010-11-09
    • 2017-06-18
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多