65

哪个更正确,为什么?

Control.BeginInvoke(new Action(DoSomething), null);

private void DoSomething()
{
    MessageBox.Show("What a great post");
}

或者

Control.BeginInvoke((MethodInvoker) delegate { 
    MessageBox.Show("What a great post");
}); 

我有点觉得我在做同样的事情,所以什么时候使用MethodInvokervs Action,甚至写一个 lambda 表达式合适?

编辑:我知道编写 lambda 与 之间并没有太大区别Action,但MethodInvoker似乎是为了特定目的而制作的。它有什么不同吗?

4

7 回答 7

85

两者都同样正确,但文档Control.Invoke说明:

委托可以是 EventHandler 的一个实例,在这种情况下,sender 参数将包含此控件,而 event 参数将包含 EventArgs.Empty。委托也可以是 MethodInvoker 的实例,或任何其他采用 void 参数列表的委托。调用 EventHandler 或 MethodInvoker 委托将比调用另一种委托更快。

因此MethodInvoker将是一个更有效的选择。

于 2009-07-22T19:55:14.197 回答
29

对于下面的每个解决方案,我运行 131072 (128*1024) 次迭代(在一个单独的线程中)。VS2010 性能助手给出以下结果:

  • 只读 MethodInvoker:5664.53 (+0%)
  • 新 MethodInvoker:5828.31 (+2.89%)
  • MethodInvoker 中的函数转换:5857.07 (+3.40%)
  • 只读行动:6467.33 (+14.17%)
  • 新行动:6829.07 (+20.56%)

在每次迭代中调用一个新的Action

    private void SetVisibleByNewAction()
    {
        if (InvokeRequired)
        {
            Invoke(new Action(SetVisibleByNewAction));
        }
        else
        {
            Visible = true;
        }
    }

在每次迭代时调用只读、内置构造函数、Action

    // private readonly Action _actionSetVisibleByAction
    // _actionSetVisibleByAction= SetVisibleByAction;
    private void SetVisibleByAction()
    {
        if (InvokeRequired)
        {
            Invoke(_actionSetVisibleByAction);
        }
        else
        {
            Visible = true;
        }
    }

在每次迭代时调用一个新的MethodInvoker 。

    private void SetVisibleByNewMethodInvoker()
    {
        if (InvokeRequired)
        {
            Invoke(new MethodInvoker(SetVisibleByNewMethodInvoker));
        }
        else
        {
            Visible = true;
        }
    }

在每次迭代时调用只读的内置构造函数MethodInvoker

    // private readonly MethodInvoker _methodInvokerSetVisibleByMethodInvoker 
    // _methodInvokerSetVisibleByMethodInvoker = SetVisibleByMethodInvoker;
    private void SetVisibleByMethodInvoker()
    {
        if (InvokeRequired)
        {
            Invoke(_methodInvokerSetVisibleByMethodInvoker);
        }
        else
        {
            Visible = true;
        }
    }

在每次迭代时调用MethodInvoker中的函数转换

    private void SetVisibleByDelegate()
    {
        if (InvokeRequired)
        {
            Invoke((MethodInvoker) SetVisibleByDelegate);
        }
        else
        {
            Visible = true;
        }
    }

呼吁“新行动”解决方案的示例:

    private void ButtonNewActionOnClick(object sender, EventArgs e)
    {
        new Thread(TestNewAction).Start();
    }

    private void TestNewAction()
    {
        var watch = Stopwatch.StartNew();
        for (var i = 0; i < COUNT; i++)
        {
            SetVisibleByNewAction();
        }
        watch.Stop();
        Append("New Action: " + watch.ElapsedMilliseconds + "ms");
    }
于 2014-09-17T09:16:06.390 回答
13

我更喜欢使用 lambdas 和 Actions/Funcs:

Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post")));
于 2009-07-22T19:56:54.880 回答
6

Action 是在 System 中定义的,而 MethodInvoker 是在 System.Windows.Forms 中定义的——使用 Action 可能会更好,因为它可以移植到其他地方。您还会发现接受 Action 作为参数的地方比 MethodInvoker 更多。

但是,文档确实表明在 Control.Invoke() 中调用 EventHandler 或 MethodInvoker 类型的委托将比任何其他类型更快。

除了它们所在的名称空间之外,我不认为 Action 和 MethodInvoker 之间存在有意义的功能差异 - 它们本质上都定义为:

public delegate void NoParamMethod();

顺便说一句,Action 有几个重载允许传入参数 - 它是通用的,因此它们可以是类型安全的。

于 2009-07-22T19:54:10.360 回答
3

同样根据 MSDN:

MethodInvoker提供了一个简单的委托,用于调用具有 void 参数列表的方法。当调用控件的 Invoke 方法时,或者当您需要一个简单的委托但不想自己定义一个委托时,可以使用此委托。

另一方面,一个动作最多可以有 4 个参数。

但我认为MethodInvokerAction之间没有任何区别,因为它们都只是封装了一个不带参数并返回void的委托

如果您查看它们的定义,您将简单地看到这一点。

public delegate void MethodInvoker();
public delegate void Action();

顺便说一句,您也可以将第二行写为。

Control.BeginInvoke(new MethodInvoker(DoSomething), null);
于 2009-07-22T19:54:01.203 回答
2

在大多数情况下,这是一个偏好问题,除非您打算重用 DoSomething() 方法。此外,匿名函数会将您的作用域变量放在堆上,可能使其成为更昂贵的函数。

于 2009-07-22T19:51:14.873 回答
1

不要忘记以某种方式检查当前是否可用控制,以避免在关闭表单时出错。

if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));
于 2017-12-20T11:55:55.003 回答