2011-06-15 124 views
6

我注意到了.NET 4.0中的一種新趨勢,特別是在潛在的多線程場景中,它避免了事件,並提供了訂閱者方法。訂閱者方法vs事件

例如,System.Threading.Tasks.TaskTask<TResult>ContinueWith()方法而不是Completed或Finished事件。另一個示例是System.Threading.CancellationToken:它有一個Register()方法而不是CancellationRequested事件。

雖然Task.ContinueWith()是合乎邏輯的,因爲它可以很容易的任務鏈(不會與事件如此優雅),而且它也允許Task<TResult>Task繼承(因爲這樣一來,Task<TResult>可以提供適當的過載,這對一個事件來說是不可能的:如果你有一個事件EventHandler在Task中完成,你所能做的就是創建另一個事件,比如事件EventHandler<TaskResultEventArgs>Task<TResult>中完成,這不是很好),但是我找不到對CancellationToken.Register()的解釋相同。

那麼,類似情況下事件的缺點是什麼?我是否也應該遵循這種模式?爲了澄清,我應該選擇哪一種?我應該什麼時候比較喜歡一個?

public event EventHandler Finished; 

// or 

public IDisposable OnFinished(Action continuation) 

非常感謝!

+0

@Jon Skeet:謝謝,我沒有注意到我的天使托架需要一些逃脫。 – ShdNx 2011-06-15 10:35:35

+0

UI事件等可以使用UI消息隊列發佈,並且與使用委託或簡單任務相比,可能會非常緩慢/沉重。 – CodingBarfield 2011-06-15 10:54:38

+0

@Barfieldmv:可以使用與Invoke/BeginInvoke相同的技術將動作調用發佈到UI線程。這不是區別。 – 2011-06-15 10:59:54

回答

2

我想使用訂閱者方法的一個好處是你有能力輕鬆指定你的委託將被執行的線程。請參閱CancellationToken.Register()的this overload

Upd:嗯,實際上你可以指定你的委託將被髮布到的同步上下文。

你是對的趨勢。 This article在MSDN Magazine中聲明如下:

新組件不應該使用基於事件的異步模式 。該 的Visual Studio異步社區 技術預覽版(CTP)包括 文檔描述基於任務的 異步模式,其中 組件返回任務和 任務對象,而不是通過 的SynchronizationContext引發事件。基於任務的 API是用.NET編程的異步 的未來。

和製品指document

發起並在TAP的 異步操作的完成是由一個單一的方法來表示 ,和 因此僅存在一個方法來命名。 這是與其中BeginMethodName和 EndMethodName方法是必需的, 和在對比的基於事件的 異步模式,或EAP,其中在 另外需要 MethodNameAsync的 IAsyncResult的圖案,或APM圖案, 到一個或多個事件,事件 處理程序委託類型和 EventArg派生類型。

事實上,照顧一件事物而不是許多事物是很好的。但是這比TAP優於EAP,而不是訂戶方法的優勢。

+0

這很有道理。方法(訂戶方法)比事件更靈活,並且問題也更少(例如事件相關的內存泄漏)。另一方面,方法感覺像是退步,因爲程序員還必須實現一個存儲回調的列表,擔心回調列表的線程安全性。所以看起來總的來說,事件比普通的_subscriber_方法更好(這裏沒有談論EAP),訂戶方法通常不值得(例如,當指定特殊的回調行爲時)。感謝你的回答! – ShdNx 2011-06-17 11:33:29