2011-03-04 97 views
5

如果我創建一個.NET類,訂閱事件與一個匿名函數是這樣的:我是否需要刪除這類事件處理程序?

void MyMethod() 
{ 
    Application.Current.Deactivated += (s,e) => { ChangeAppearance(); }; 
} 

將這個事件處理程序是根讓我的類被垃圾收集?

如果不是,wohoo!但如果是這樣,你能告訴我去除語法嗎?只是使用 - =使用相同的代碼似乎是錯誤的。

回答

3

您可以使用一個「真實」的方法,西蒙D.建議,或這樣做:

EventHandler handler = null; 
handler = (s,e) => { 
    Application.Current.Deactivated -= handler; 
    ChangeAppearance(); 
}; 
Application.Current.Deactivated += handler; 

由於這是有點醜陋並且擊敗使用Lambda是succint的目的,我倒是可能要重構它的方法。但知道還有什麼作用是有用的。

警告:不用說,你必須是超級超級小心與handler在那裏你訂閱事件,它實際上是調用該點的點之間的所有價值不亂,否則取消訂閱部分將無法正常工作。

+0

我喜歡這裏的succint風格。爲了我的需要,這應該完美地工作。感謝您抽出寶貴時間寫下來! – jschroedl

3

我認爲您確實需要取消訂閱,因爲事件提供者(應用程序)的生命 - 或者至少可以生存 - 比您的消費者更長。因此,每個訂閱實例在應用程序仍然存在時死去都會造成內存泄漏。

您正在訂閱該活動的匿名代理人。 這就是爲什麼你不能以同樣的方式取消訂閱,因爲你不能再解決它。 實際上,您在訂閱的同一時刻創建方法,並且不存儲任何指向新創建的方法的指針。

如果你稍微改變你的方案中使用「真實」的方法,你可以很容易地從事件退訂您訂閱同樣的方式:

Application.Current.Deactivated += ChangeAppearance; 
Application.Current.Deactivated -= ChangeAppearance; 
private void ChangeAppearance(object sender, EventArgs eventArgs) 
{ 
    throw new NotImplementedException(); 
} 
+0

感謝您的確認懷疑。 - 約翰 – jschroedl

1

這的確是防止垃圾收集泄漏。周圍有辦法 - WeakReference是更好的之一。

This link有一個很好的對話和很好的答案給你。

+0

感謝您的指針。那些傢伙變得很漂亮! – jschroedl

2

你一定要清理參考。如果有任何疑問,您可以輕鬆地使用您自己的靜態事件進行測試。

static class MemoryLeak 
{ 
    static List<Action<int>> list = new List<Action<int>>(); 
    public static event Action<int> ActivateLeak 
    { 
     add 
     { 
      list.Add(value); 
     } 
     remove 
     { 
      list.Remove(value); 
     } 
    } 
} 

然後通過在remove函數中設置一個斷點,您可以看到您的引用沒有被清除。

class Program 
{ 
    static void Main(string[] args) 
    { 
     foo f = new foo(); 
     MemoryLeak.ActivateLeak += o => f.bar(); 
     f.tryCleanup(); 
    } 
} 

class foo 
{ 
    public void bar() 
    { } 

    public void tryCleanup() 
    { 
     MemoryLeak.ActivateLeak -= o => bar(); 
    } 
} 

作爲Simon解決方案的替代方案,您可以使用第二個閉包創建可以傳遞的「分離」動作。

foo f = new foo(); 
Action<int> callfoo = o => f.bar(); 
MemoryLeak.ActivateLeak += callfoo; 
Action cleanUp =() => MemoryLeak.ActivateLeak -= callfoo; 

// Now you can pass around the cleanUp action and call it when you need to unsubscribe from the event. 
cleanUp(); 
相關問題