我的問題是,而不是使用「對Action的引用」,爲什麼「對MethodInfo的引用」有訣竅?我假設也應該收集methodinfo。
不,這不是真的MethodInfo
vs Action
這個技巧。這是別的,但我不得不承認,這篇文章寫得不好,可能會令人困惑。讓我試着解釋一下。
活動和GC
假設你有一個事件類叫做Click
。類是:Button
比方說,你有另一個類訂閱事件從Button
這樣的:
public class Subscriber1
{
public Subscriber1(Button button)
{
button.Click += ClickHander;
}
private void ClickHander(object sender, EventArgs e)
{
// ...
}
public void UnSubscribe()
{
button.Click -= ClickHandler;
}
}
現在如何按鈕類知道是單擊按鈕時誰通知?那麼,它會保留所有已訂閱的類的引用。所以在上面的例子中,它將持有對Subscriber1
類實例的引用。每當按鈕被點擊時,它將通知Subscriber1
的實例。所以,如果我們這樣做,會發生什麼:
subcriber1Instance = null;
會發生什麼事是,如果button
實例仍然活着,GC將不會收集subscriber1Instance
。爲什麼?因爲它的根源:button
實例持有對其的引用。這就是爲什麼我們應該做這個:
subscriber1Instance.UnSubscribe();
subcriber1Instance = null;
在現實Subscriber1
應該實現IDisposable並做退訂那裏,但這個答案的關鍵不在於。所以我保持簡單,所以我們不會失去焦點。
當我們取消訂閱button
實例的Click
事件時,subscriberIntance
不再是根源,它可以由GC清理。
那麼,什麼是文章在做什麼?
在這篇文章中,作者試圖解決開發人員忘記取消這一問題,並因此導致內存泄漏問題。請注意,這是一種方式:只有當發佈者超過訂閱者時,纔會保持訂閱者活着,而不是相反。因此,如果發佈者準備好GC,訂閱者將無法保持活動狀態。
基本上,作者所說的是訂戶不應該直接訂閱該事件,因此它不會導致button
對其進行嚴格引用。相反,用戶應從WeakReference
派生,並在訂閱時將其傳遞給button
。就像這樣:
private class WeakSubscriber1 : WeakReference
{
public WeakSubscriber1(Subscriber1 target) : base(target) { }
public void ClickHander(object sender, EventArgs args)
{
Subscriber1 b = (Subscriber1)this.Target;
if (b == null)
{
Button c = sender as Button;
if (c != null)
{
c.MyEvent -= new EventHandler(this.ClickHandler);
}
}
else
{
b.Handler1(sender, args);
}
}
}
要使用上面的會是這樣:
Subscriber1 sub1 = new Subscriber1();
WeakSubscriber1 weak = new WeakSubscriber1(sub1);
Button button = new Button();
button.Click += weak.ClickHandler();
現在button
是一家控股弱引用。這意味着當sub1
爲空並且button
觸發該事件時,則weak
將檢查sub1
是否爲空。如果是,則會檢查button
是否仍然存在。如果兩者都是真的,那麼它將退訂。現在sub1
不再訂閱button.Click
,因此GC可以收集它。
@Rob是的,我同意你的最後一句話。然而,我感到困惑的是,作者暗示如果您在WeakReference中保留對它的引用(我是對的?),那麼爲什麼要保留對MethodInfo的引用? –