我一直在使用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