我在这里看一个调解员原型https://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/。
作者指出"我的第一个想法是在WeakReference中存储对Action的引用。由于垃圾收集器将丢弃仅由WeakReference对象引用的对象,因此看起来这可以解决问题。不幸的是,它并不那么简单。这种方法的问题是GC会丢弃Action实例,因为它只被WeakReference引用!"
我的问题不是使用"对Action"的引用,为什么"对MethodInfo的引用"做诀窍?我假设也应该收集methodinfo。
提前致谢。
答案 0 :(得分:2)
我的问题不是使用"对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
。为什么?因为它是root的:button
实例持有对它的引用。这就是为什么我们应该这样做:
subscriber1Instance.UnSubscribe();
subcriber1Instance = null;
实际上Subscriber1
应该实现IDisposable并在那里取消订阅,但这个答案的重点不是那个。所以我保持简单,所以我们不会失去焦点。
当我们取消订阅Click
实例的button
事件时,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可以收集它。