繁体   English   中英

我是否需要取消订阅局部变量的匿名事件处理程序?

[英]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的实例

  • 由lambda表示的匿名方法已从FooEvent的调用列表中删除
  • 可以将其附加到的Foo实例进行收集

这是因为该事件(仅是普通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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM