2009-07-22 95 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"));