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

Gra*_*ton 8 c# dispose winforms

我有以下课程

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
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*eet 8

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

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

不需要与其他成员做任何事情,因为您现在IDiposable因为这一原因而实施.

那么,你需要从这个课程中进一步推导出来吗?


1我确实理解这是标准的推荐模式,虽然我建议您阅读Joe Duffy等人的建议,了解更多细节 - 它们都会变得非常复杂.


Jos*_*osh 5

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

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

实现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
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 除非你的类拥有非托管资源,否则你不想添加终结器(`~MyObject(){Dispose(false);}`).在这种情况下,最好将非托管资源句柄包装在`SafeHandle`中.通常,实现"IDisposable"的精心设计的对象将从"CriticalFinalizerObject"派生,或者不具有终结器. (3认同)