2010-05-27 30 views
9

最近我一直在研究內存管理,並且一直在研究如何管理事件,現在,我看到了事件訂閱的顯式添加/刪除語法。顯式事件添加/刪除,誤解?

我認爲這很簡單,添加/刪除只允許我執行其他邏輯,當我訂閱和取消訂閱?我是否明白了,還是有更多呢?

另外,雖然我在這裏,任何清理我的事件處理建議/最佳做法。

回答

3

添加/刪除語法通常用於將事件實現「轉發」到另一個類。

清理訂閱(不是「事件句柄」)最好通過執行IDisposable來完成。

更新:對於哪個對象應該實現IDisposable有一些變化。 Rx團隊從設計角度做出了最好的決定:訂閱本身是IDisposable。常規.NET事件沒有表示訂閱的對象,因此選擇是在發佈者(定義事件的類)和訂閱者(​​通常是包含正在訂閱的成員函數的類)之間進行的。儘管我的設計本能更願意讓用戶IDisposable,但大多數真實世界的代碼使得發佈者IDisposable:這是一個更容易的實現,並且可能存在沒有實際訂閱者實例的情況。

(也就是說,如果代碼實際上清理事件訂閱的。大多數代碼沒有。)

+0

哈,我在與同事交談時將它們稱爲訂閱,但當我發佈一個問題時,我使用了錯誤的術語。 感謝您的澄清。 – Hammerstein 2010-05-27 18:58:45

6

是,在添加/刪除語法,讓你實現你自己的訂閱邏輯。當你將它們排除(事件的標準符號)時,編譯器會生成標準實現。這就像自動屬性。

在下面的示例中,事件1和事件2之間沒有真正的區別。

public class Foo 
{ 
    private EventHandler handler; 
    public event EventHandler Event1 
    { 
    add { handler += value; } 
    remove { handler -= value; } 
    } 

    public event EventHandler Event2; 
} 

但是,這是從「清理」處理一個獨立的主題。訂閱類應該做退訂。出版社對此非常不利。
想象一下,可以「清理」其事件的訂閱列表的類。只有當它被釋放時它纔會明智地做到這一點,然後它不太可能有生產力,因爲處置後的類通常在被處置後不久就變得可收集。

+1

我相信最終用戶不能這樣做:'Foo foo = ...; foo.Event1(sender,e);'但可以做'foo.Event2(null,null);'。 – user7116 2010-05-27 19:11:26

+0

感謝您的示例和澄清。我以爲我擁有它,但我一直在想它! 我會在一個單獨的問題上發佈我關於內存管理的問題,因爲我認爲我想問的更多。 – Hammerstein 2010-05-27 19:15:33

+0

我錯了,在這兩種情況下都會收到錯誤消息,但在第二種情況下會收到另一個錯誤消息:錯誤CS0070:事件'Program.Foo.Event2'只能出現在+ =的左側或 - =(從「Program.Foo」類型內使用)除外。 – user7116 2010-05-27 19:17:06

9

添加/刪除特性基本上都採用了設置/獲取與其他成員屬性的相同的邏輯的。 它允許你創建一些額外的邏輯,同時註冊了一個事件,封裝事件本身。

爲什麼要做這件事的一個很好的例子就是在不需要的時候停止額外的計算(沒人在聽這個事件)。

例如,讓我們說,事件是由定時器觸發,而我們不希望,如果沒有一個被註冊到該事件的定時器工作:

private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); 
private EventHandler _explicitEvent; 
public event EventHandler ExplicitEvent 
{ 
    add 
    { 
     if (_explicitEvent == null) timer.Start(); 
     _explicitEvent += value; 
    } 
    remove 
    { 
     _explicitEvent -= value; 
     if (_explicitEvent == null) timer.Stop(); 
    } 
} 

你可能想用對象鎖定添加/刪除(一個事後想法)...