我一直在使用WeakEventManager來避免內存泄漏,並且我開始過度使用它們。 我創建擴展方法,例如,用於INotifyPropertyChanged的,如:WeakEventManager擁有對用戶的引用
public static void AddWeakPropertyChanged(this INotifyPropertyChanged item, Action handler)
{
PropertyChangedEventManager.AddHandler(item, (s, e) => handler(e.PropertyName), string.Empty);
}
現在我很快意識到,這是行不通的。事實上,你不能真正使用匿名方法進行弱事件處理。 (如果我理解正確,那麼編譯器爲它創建一個'閉包類'(用於存放引用的值),它具有處理程序,但由於您的閉包類沒有被引用到任何地方,GC將清除它,並且事件處理程序將不會被稱爲)
問題1:是否正確?我的意思是說它是正確的,那麼當對弱事件處理程序使用匿名方法(或lambda)時,只有在GC未同時運行的情況下才會調用處理程序(例如,它是不確定的)?
那麼,我想這樣,所以我做了一些單元測試,以確保我得到它的權利。這似乎還好吧,直到我打了以下的單元測試:
class DidRun
{
public bool Value { get; set; }
}
class TestEventPublisher
{
public event EventHandler<EventArgs> MyEvent;
public void RaiseMyEvent()
{
if (MyEvent != null)
MyEvent(this, EventArgs.Empty);
}
}
class TestClosure
{
public DidRun didRun { get; set; }
public EventHandler<EventArgs> Handler { get; private set; }
public TestClosure()
{
this.Handler = new EventHandler<EventArgs>((s, e) => didRun.Value = true);
}
}
[TestMethod]
public void TestWeakReference()
{
var raiser = new TestEventPublisher();
var didrun = new DidRun();
var closure = new TestClosure { didRun = didrun };
WeakEventManager<TestEventPublisher, EventArgs>.AddHandler(raiser, "MyEvent", closure.Handler);
closure = null;
GC.Collect();
GC.Collect();
raiser.RaiseMyEvent();
Assert.AreEqual(false, didrun.Value);
}
問題2:任何人都可以解釋我爲什麼會發生這種測試失敗?期望:在這裏,我沒有任何關閉(我把它們拿出來,以確保發生了什麼),我只是有一個對象(閉包),訂閱了一個與WeakEventManager事件,然後我放棄引用它(closure = null;)。
我期待着2 GC.Collect()調用,以清理我的舊閉包類,所以WeakEventManager將放棄訂閱者,並且不運行處理程序,但測試失敗。有任何想法嗎?
編輯:對不起,一般的論據是不可見的,現在他們
哇,非常感謝,我被這個困惑,而事實上我忽略,即在值傳遞是很難參照處理。現在我明白了。再次感謝您的幫助! – MBoros 2013-10-22 10:54:52