2012-08-14 22 views
4

我正在編寫GUI應用程序一段時間,而且我總是使用MethodInvoker + lambda函數來執行跨線程訪問。使用MethodInvoker而無需調用

從例子中我發現,我總是看到這樣的東西:

1版

if (InvokeRequired) 
{ 
    Invoke(new MethodInvoker(() => 
    { 
     Label1.Text = "Foobar"; 
    }); 
} 
else 
{ 
    Label1.Text = "Foobar"; 
} 

然而這會導致代碼的重複 - >大壞蛋給我。

那麼這有什麼問題呢?

2版

MethodInvoker updateText = new MethodInvoker(() => 
    { 
     Label1.Text = "Foobar"; 
    }); 

if (InvokeRequired) 
{ 
    Invoke(updateText); 
} 
else 
{ 
    updateText(); 
} 

現在我的功能在一個可變捆紮並在適當的時候與調用或作爲函數指針調用它。版本2是否更糟?或者,我是不好的做法,使用匿名函數呢?

回答

10

沒有什麼地方錯了...但你可以添加一個擴展方法,使這一切有點漂亮:

public static void InvokeIfNecessary(this Control control, 
            MethodInvoker action) 
{ 
    if (control.InvokeRequired) 
    { 
     control.Invoke(action); 
    } 
    else 
    { 
     action(); 
    } 
} 

然後,你可以寫:

this.InvokeIfNecessary(() => Label1.Text = "Foobar"); 

更整潔:)

有一個非常輕微性能缺點創建一個委託時,你不需要,但它幾乎肯定是微不足道的 - concentr吃了乾淨的代碼吃了。

請注意,即使你不想做,你仍然可以使你的變量聲明簡單在現有代碼:

MethodInvoker updateText =() => Label1.Text = "Foobar"; 

這是使用一個獨立的變量的一個好處 - 你不需要new MethodInvoker位告訴你想要什麼類型的委託的lambda表達式...

+0

不錯,認爲我有2個問題:-)不知道更短的Lambda選項。另外,我認爲擴展方法更加優雅。它使我能夠更強調我在做什麼(InvokeIfRequired)。這有必要把第二個參數給Invoke?至少'Form'有一個arg超載? – Nebula 2012-08-14 08:02:31

+0

@Nebula:不,看起來你是對的。我首先查看了更一般的'ISynchronizeInvoke'版本。將編輯這個案例。 – 2012-08-14 08:10:54

+0

好的,謝謝。我實際上剛剛測試過這種方法,我對此非常滿意。它使很好的乾淨的代碼。我添加了一個'control.Isdisposed'和'control.Disposing'後衛來使它的製作值得,再次感謝! – Nebula 2012-08-14 08:17:13

2

版本2是否更糟的性能?或者,我是不好的做法,使用匿名函數呢?

沒有版本2更好,不用擔心它的性能問題。而不是使用匿名函數,你也可以定義一個方法:

public void SetLabelTextToFooBar() 
{ 
    Label1.Text = "Foobar"; 
} 

然後:

if (InvokeRequired) 
{ 
    Invoke(SetLabelTextToFooBar); 
} 
else 
{ 
    SetLabelTextToFooBar(); 
} 

或簡單地用一個BackgroundWorker將在自動執行所有的回調(如RunWorkerCompletedProgressChanged)主UI線程,以便您不需要檢查InvokeRequired

+0

對於這個例子,我同意你的看法。當你有一個更真實的例子時,小包裝方法的數量往往會增長得相當快。當我使用後臺工作人員進行大量UI更新時,我傾向於儘可能減少Invoke中的工作量。這意味着我將不得不做出很多功能來做到這一點,這往往會隨着時間的推移而變得模糊。 – Nebula 2012-08-14 07:54:34

2

另一種做法做下去:

Invoke((MethodInvoker)delegate 
{ 
    Label1.Text = "Foobar"; 
}); 
相關問題