繁体   English   中英

取消订阅活动

[英]unsubscribing from events

在WinForms中,我可以使用IDisposable实现取消订阅表单事件(例如:Activated,Load,ContextMenuChanged等)来帮助垃圾回收吗?


取消订阅MSDN

为防止在引发事件时调用事件处理程序,请退订该事件。 为了防止资源泄漏,应该在处理订阅者对象之前取消订阅事件。 取消订阅事件之前,发布对象中作为事件基础的多播委托具有对封装了订户的事件处理程序的委托的引用。 只要发布对象拥有该引用,垃圾回收就不会删除您的订阅者对象。

是的,您可以,但是,取决于有多少事件,我会说这将属于微优化类别。

是的,您可以,但是如果事件处理程序是在您自己的类中定义的,并且也是在同一实例中定义的,那么您不必取消订阅该事件,因为发布者和订阅者是同一对象。 因此,没有其他参考对象。

如果您订阅对象的处理对象B的事件,那么就值得在对象B.事件,否则构成了这一事件将举行两个对象引用的多播委托退订。 阻止垃圾收集器收集两个对象。

要添加到@Maarten的答案中 ,而不是在Form中处理“您自己的”事件,通常更简单的方法是重写调用这些事件的众多protected virtual方法中的任何一个。

即,而不是附加到Load事件:

this.Load += DoStuff;

private void DoStuff(object sender, EventArgs e) 
{
    // do stuff
}

您应该简单地重写OnLoad方法,完全不必考虑取消订阅:

protected override void OnLoad(EventArgs e)
{
    // do stuff
    ...

    // call the base method to fire the event 
    // for external listeners
    base.OnLoad(e);
}  

这为您留有仅用于外部对象事件的处理程序,当您使用完它们后应将其分离。

这也是为什么对每个公共事件始终使用protected virtual OnXXXX方法是一个好习惯的原因:允许派生类触发该事件并在执行该操作之前添加其他处理逻辑。

在通常的WinForms用例中,发布者和订阅者会在一起并被同时处置。 预订按钮OnClick事件通常是包含按钮的窗口类的方法。 在不删除按钮的情况下从内存中删除窗口是没有意义的。

在这些情况下,您无需退订(据我所知)。

仅当您的订阅者类别在发布者之前被处置时才有意义,例如,另一个窗口对一个窗口的OnLoad做出反应。 然后使用IDisposable将是一个好主意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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