[英]How do I unsubscribe from a lambda event that needs variables passing into it?
[英]Do i have to unsubscribe from anonymous event handlers of local variables?
如果我有一个看起来像这样的代码:
public void Foo()
{
Bar bar = new Bar();
bar.SomeEvent += (sender, e) =>
{
//Do something here
};
bar.DoSomeOtherThingAndRaiseSomeEvent();
}
方法超出范围时会收集bar
,还是我必须手动取消订阅该事件以防止由于引用SomeEvent
而导致内存泄漏?
您的情况还不错; 事件订阅者不会阻止发布者被收集,但是可能发生相反的情况。
例如,
class Foo
{
public event EventHandler FooEvent;
void LeakMemory()
{
Bar bar = new Bar();
bar.AttachEvent(this);
}
}
class Bar
{
void AttachEvent(Foo foo)
{
foo.FooEvent += (sender, e) => { };
}
}
在这种情况下,只有在LeakMemory
情况下才能收集在LeakMemory
创建的Bar
的实例
FooEvent
的调用列表中删除 这是因为该事件(仅是普通delegate
实例上的某种语法糖)保留在调用时将要调用的委托列表上,并且这些委托中的每一个又具有对其附加对象的引用(在这种情况下,为Bar
的实例)。
请注意,我们在这里仅讨论集合资格 。 正因为它的资格并没有说什么时候 (甚至,真的, 如果 ),它会被收集,只是它可以是任何东西。
好吧,对象bar
引用不会立即被自动垃圾回收……只是bar
变量不会阻止它被垃圾回收。
事件处理程序也不会阻止Bar
的实例被垃圾回收-“正常”问题是事件处理程序使事件的订阅者无法被垃圾回收(如果它使用实例方法或捕获“ this”)在匿名函数中)。 通常不会影响发布者被垃圾回收。 只需记住发布者需要保留对所有订阅者的引用-订阅者不需要记住其订阅的内容,除非订阅者明确希望以后取消订阅或使用其他成员。
假设没有其他因素可以使Bar
实例保持活动状态,则您的代码应该没问题。
以上答案是正确的; 我只是想做个笔记。 仅当您保留对委托/ lambda的其他引用时,才能取消订阅用作处理程序的匿名委托。 这是因为lambda是“函数文字”,有点像字符串文字,但是与字符串不同,在确定相等性时不会在语义上对它们进行比较:
public event EventHandler MyEvent;
...
//adds a reference to this named method in the context of the current instance
MyEvent += Foo;
//Adds a reference to this anonymous function literal to MyEvent
MyEvent += (s,e) => Bar();
...
//The named method of the current instance will be the same reference
//as the named method.
MyEvent -= Foo;
//HOWEVER, even though this lambda is semantically equal to the anonymous handler,
//it is a different function literal and therefore a different reference,
//which will not match the anonymous handler.
MyEvent -= (s,e) => Bar();
var hasNoHandlers = MyEvent == null; //false
//To successfully unsubscribe a lambda, you have to keep a reference handy:
EventHandler myHandler = (s,e) => Bar();
MyEvent += myHandler;
...
//the variable holds the same reference we added to the event earlier,
//so THIS call will remove the handler.
MyEvent -= myHandler;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.