2009-07-22 39 views
51

哪一个更正确?为什么?MethodInvoker vs Action for Control.BeginInvoke

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

我有点觉得我做同样的事情,所以是用MethodInvoker VS Action,甚至写一个lambda表达式正确的时间是什么时候?

编辑:我知道确实没有多少写一个lambda VS Action之间的差异,但好像MethodInvoker为特定目的而作出。它做了什么不同吗?

+0

看看这个问题,以及http://mark-dot-net.blogspot.com.uy/2014/07/six-ways-to-initiate-tasks-on-another.html – 2016-09-08 14:54:54

回答

71

二者都同样是正确的,但是对于Control.Invoke文档指出:

委托可以是 事件处理程序的一个实例,在这种情况下,发送者 参数将包含这样的控制, 和事件参数将包含 EventArgs.Empty。代表也可以是MethodInvoker的一个实例,或 任何其他代理都需要一个void 参数列表。对 EventHandler或MethodInvoker委托人 的呼叫将比对另一个 类型的委托的呼叫要快。

所以MethodInvoker将是一个更有效的选择。

+0

感谢Jon,但是什么让MethodInvoker比没有参数的Action调用更有效率? – 2009-07-22 19:58:48

2

这是优先考虑在大多数情况下的事,除非你打算重用DoSomething的()方法。此外,匿名函数会将您的作用域变量放在堆上,可能会使其成为更昂贵的函数。

3

而且每MSDN:

MethodInvoker提供了用于调用与空隙参数列表的方法的简单的委托。这个委托可以在调用控件的Invoke方法时使用,或者当你需要一个简单的委托但不想自己定义一个时。

在另一方面的动作可能需要长达4个参数。

但我不认为这是MethodInvoker行动,因为它们都只是封装的委托,不采取paremter和回报之间有什么区别无效

如果你看看他们的定义你只会看到这一点。

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

顺便说一句,你也可以写你的第二个行。

Control.BeginInvoke(new MethodInvoker(DoSomething), null); 
+0

你甚至可以将其重写为: Control.BeginInvoke(new MethodInvoker(DoSomething)); (新)MethodInvoker(()=> {DoSomething();})); – juFo 2012-06-28 15:32:29

4

行动在系统中定义的,而MethodInvoker在System.Windows.Forms的定义 - 您可以使用动作会更好,因为它是可移植到其他地方。您还可以找到更多接受Action作为参数的地方,而不是MethodInvoker。

然而,文件确实表明,调用类型的事件处理程序或MethodInvoker在Control.Invoke()的代表将超过任何其他类型的更快。

除了他们在namepsace,我不相信这是行动和MethodInvoker之间有意义的功能区别 - 它们基本上都定义为:

public delegate void NoParamMethod(); 

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

+4

反过来说,Action只在.NET 3.5中定义... – 2009-07-22 19:58:15

8

我更喜欢使用lambdas和操作/ funcs中:

Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post"))); 
18

对于每个溶液波纹管我运行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%)

呼叫到一个新行动在每次迭代

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

呼叫到一个只读,建立构造,行动在每次迭代

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

呼叫到一个只读的,在每次迭代

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

调用该函数铸于MethodInvoker建立在构造函数中,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"); 
    } 
0

不要忘记以某种方式检查当前是否有控件可用,以避免在关闭窗体出现错误。

if(control.IsHandleCreated) 
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));