取消订阅活动

时间:2013-09-17 12:33:03

标签: c# .net winforms events

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


取消订阅MSDN

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

4 个答案:

答案 0 :(得分:4)

但是,你可以根据有多少事件我会说这将属于微优化类别。

答案 1 :(得分:3)

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

如果订阅对象A来处理对象B的事件,则 值得取消订阅对象B中的事件。否则,作为事件基础的多播委托将保留对这两个对象的引用。并且阻止垃圾收集器收集这两个对象。

答案 2 :(得分:1)

要添加到@Maarten's answer,而不是在Form内处理“您自己的”事件,覆盖调用这些事件的众多protected virtual方法中的任何一个通常要简单得多。< / p>

即。而不是附加到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方法的好习惯:允许派生类触发事件并在执行之前添加其他处理逻辑。

答案 3 :(得分:1)

在通常的WinForms用例中,发布者和订阅者粘在一起并同时处理。订阅按钮OnClick事件通常是包含按钮的窗口类的方法。如果没有删除按钮,从内存中删除窗口是没有意义的。

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

唯一重要的是,如果您的订阅者类别在发布者之前被处理掉,例如另一个窗口响应窗口的OnLoad。然后使用IDisposable是个好主意。