使用IDisposable取消订阅事件 - 我是否需要在处理中放置其他内容?

时间:2010-01-13 06:34:05

标签: c# winforms dispose

我有以下课程

public class Presenter: IDisposable
{
   public IView View
   {get;private set;}

   //snip other object reference, all managed
   public Presenter(IView view)
  {
     View=view;
     View.MouseUp += MouseUpEvent;
  }

  public void MouseUpEvent()
  {
    //do whatever you want to do on mouse up
  }

  public void Dispose()
  {
    View.MouseUp -= MouseUpEvent;
    // no more manual disposing
  }
}

现在的问题是,我是否正确实施了Dispose()方法?或者我是否需要手动处理所有其他托管对象,因为我已明确定义Dispose()

我认为GC很聪明,可以自行处理(事件订阅除外),即使没有我手动执行它。我是对的吗?

2 个答案:

答案 0 :(得分:8)

如果你选择在构造函数中订阅,那么这看起来很合理。我会回应乔希的观点,认为这可能不是最好的方法。另一方面,它可能是实现目标的最简单方式,这始终是一件好事。我不会假装成为UI模式方面的专家:提出问题,我会假设这是你想要的工作方式,并解决问题本身:)

我个人觉得Josh的规定模式 1 对于简单的场景来说过于复杂 - 你的方法很好,只需要改变一下:让你的课程密封。如果想要密封课程,你应该选择Dispose(bool)选项(但没有终结器),因为子类可能还需要处理东西,并且可能需要一个终结器。没有衍生类型的可能性,生活更简单(因为它经常是这样)。

需要与其他成员做任何事情,因为你现在因为这个原因而实施IDiposable

那么,您是否需要从这个课程中进一步推导出来?


1 我确实理解这是标准的推荐模式,尽管我建议您阅读Joe Duffy et al的建议以获取更多详细信息 - 它可以全部获得非常复杂。

答案 1 :(得分:5)

就个人而言,我会避免在构造函数中挂钩/取消挂钩事件并进行处理。相反,我会将代码添加到View get / set访问器并将其添加到那里。但是如果在附加视图时放置Presenter,我就不会费心去清理它了。如果需要显式分离,可以从演示者中明确分离视图。

话虽如此,这就是我对IDisposable的了解。

implementing IDisposable的推荐方法是使用受保护的Dispose(bool)方法来执行操作。原因是,您希望区分显式处理和最终化处理(垃圾收集)。

当您因为显式Dispose()调用而被处置时,可以触摸托管对象,并且您应该处理您创建的还需要处理的任何内容。因此,只有在处理= true时才会这样做。

但如果有人(你)忘记调用Dispose并调用终结器,那么你将在垃圾收集(disposing = false)之后被处理掉,并且你不想触摸任何托管对象,因为它们可能已经完成了。在这种情况下,你唯一需要释放的是非托管资源,如Win32句柄等。

最后,当显式调用Dispose()时,你会注意到我调用了GC.SupressFinalize(this)这是垃圾收集器的性能提示。它让它知道在收集对象时不需要最终确定对象。最终确定并不便宜。

class MyObject : IDisposable {

    ~MyObject() {
        Dispose(false);
    }

    public void Dispose() {
        Dispose(true);
        GC.SupressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) {
        if (disposing) {
            // dispose of managed resources
        }
        // dispose of unmanaged resources
    }

}