我有以下课程
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很聪明,可以自行处理(事件订阅除外),即使没有我手动执行它。我是对的吗?
答案 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
}
}