2009-04-21 74 views
16

我不確定是否完全清楚附着在對象中的事件的影響。在什麼情況下脫離必要的事件?

這是我目前的理解,正確的或複雜:

1.附加到地方級賽事中不需要拆卸

例子:

this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);

public event EventHandler OnMyCustomEvent = delegate { };

我假設當你的ob物品被丟棄或垃圾收集,功能被解除分配並且會自動脫離事件。

2.附加到對象,你不再需要的(= NULL;)必須從

實例分離: 附加到定時器的經過的事件,你只響應一次。我假設你需要將Timer存儲在本地變量中,以便在事件觸發後分離Elapsed事件。因此,宣佈計時器在本地方法的範圍,像這樣將導致泄漏:

System.Timers.Timer myDataTimer = new System.Timers.Timer(1000); myDataTimer.Elapsed += new System.Timers.ElapsedEventHandler(myDataTimer_Elapsed);

3.附加到事件在本地對象類並不需要處置?

例如,如果您有一個ObservableCollection,您創建,監視並讓它死亡。如果使用本地私有函數附加到CollectionChanged事件,那麼當您的類被垃圾回收時,此函數是否不會釋放,導致ObservableCollection也被釋放?

我確定我有地方我已經停止使用對象,並未能從事件(例如,我做的定時器例子)分離,所以我正在尋找一個更清晰的解釋如何工作。

回答

22

我認爲你讓它比它需要更復雜。你只需要記住兩件事:

  • 當你訂閱一個事件時,事件的「所有者」(發佈者)通常保持對你訂閱的委託的引用。
  • 如果您使用實例方法作爲委託的操作,那麼委託會引用其「目標」對象。

這意味着,如果你寫:

publisher.SomeEvent += subscriber.SomeMethod; 

然後subscriber將沒有資格進行垃圾回收之前publisher是,除非你以後退訂。

注意,在許多情況下,subscriber只是this

publisher.SomeEvent += myDataTimer_Elapsed; 

等同於:

publisher.SomeEvent += this.myDataTimer_Elapsed; 

假定它是一個實例方法。

沒有只是由於事件訂閱的逆向關係 - 換句話說訂閱者不會讓發佈者保持活躍狀態​​。

請參閱my article on events and delegates瞭解更多信息,順便說一下。

+0

你完全正確,我過於複雜的事情。在尋找示例時,幾乎所有人都表現出與事件分離,這隻會讓我相信訂戶可以讓發佈商保持活力。 – 2009-04-21 19:38:31

1

,你必須從事件退訂相關的情況是這樣的:

public class A 
{ 
    // ... 
    public event EventHandler SomethingHappened; 
} 

public class B 
{ 
    private void DoSomething() { /* ... */ } // instance method 

    private void Attach(A obj) 
    { 
     obj.SomethingHappened += DoSomething(); 
    } 
} 

在這種情況下,當你處理一個B的,仍然會有來自obj的懸空參考吧事件處理器。如果您想要回收B的內存,則需要首先從相關事件處理程序中分離B.DoSomething()

如果事件訂閱行這個樣子,當然,你可能會遇到同樣的事情:

obj.SomethingHappened += someOtherObject.Whatever.DoSomething(); 

現在是someOtherObject這對鉤和垃圾回收是不可能的。

3

其餘的引用阻止垃圾回收有一個更多的效果,可能是顯而易見的,但這個線程中還沒有說明;附加的事件處理程序也將被執行。

我已經經歷過幾次。一個是當我們有一個應用程序越來越慢,運行時間越來越慢。應用程序通過加載用戶控件以動態方式創建用戶界面。容器使用戶控件訂閱了環境中的某些事件,並且其中的一個未在控件「卸載」時取消訂閱。

過了一段時間,這導致大量的事件偵聽器在每次引發特定事件時都被執行。這當然會導致嚴重的競爭條件,當很多「睡眠」實例突然醒來並嘗試對相同的輸入進行操作時。

總之;如果你編寫代碼來連接一個事件監聽器,確保您在不再需要時立即發佈。我幾乎敢承諾,它將在未來的某個時刻至少讓你至少頭疼一次。

相關問題