2010-03-28 96 views
12

是否有一種簡單的方法遍歷訂閱給定事件的處理程序?我的問題是,客戶訂閱,但忘記取消訂閱,所以發生內存泄漏。我需要一種方法讓對象在Dispose方法中斷開其事件的所有處理程序,這樣就不會發生泄漏 - 至少不是因爲事件。C#如何取消訂閱給定事件的所有事件處理程序?

回答

11

設置爲null,您的活動:MyEvent = null;

但它確實是更好地使客戶從你的事件退訂。

+1

在C#中無法將事件設置爲null。 – 2011-05-25 23:35:50

+8

事實上,如果你是在聲明事件的類內部的話,這是可能的。 – 2011-05-26 03:03:46

+1

你是對的。 – 2011-05-31 17:29:15

9

另一種方法是使用所謂的「弱代表」模式。當您使用這種技術時,事件引用客戶端只使用WeakReference,它不會將它們保留在內存中。當客戶不再從應用程序的其他部分引用時,客戶端將被垃圾回收(並且處理程序也可以在客戶端收集時自動取消註冊)。

這通常用於解決客戶「忘記」退訂.NET事件的問題,所以它聽起來像這可能很適合您的問題。

7

只有當另一個對象(偵聽器)死於對象(事件源)之前,內存泄漏纔會發生。在這種情況下,事件源仍然保留對偵聽器的引用,這會阻止收集偵聽器。當事件源死亡時,也可以收集未訂閱的偵聽器。

如果事件源在偵聽器之前死亡,則不會阻止稍後收集偵聽器,此時將其所有其他引用都設置爲空。

這意味着,事件源Dispose方法是不正確的地方解決這個問題。它只能在偵聽器代碼中解決。簡單地說,除了要求你的客戶編寫乾淨的代碼之外,你什麼也做不了。

1

在撰寫本文時,最準確的答案是最不受歡迎的。

你可以使事件處理函數無效,但是在它的所有者被zapped之後無論如何都會被zapped - 它的超級整潔沒有錯,但是像Alex說的那樣,問題不在這裏。

Adi的源代碼類將允許偵聽對象在收集時自動收集,毫無疑問。所以問題在於Adi的源對象保持開放,可能來自客戶代碼中的一長串引用。

以下博客文章還介紹了Adi正在闡述的解決方案,並解釋了爲什麼不必要。

http://weblogs.sqlteam.com/mladenp/archive/2007/10/24/C-Care-about-Event-Memory-Leaks-with-Delegate.GetInvocationList.aspx

相關問題