C#如何实现Dispose方法

我需要一些关于Dispose方法实现的建议。

在我们的应用程序中,用户设计自己的UI。 我有一个预览窗口,显示UI的外观。 在此UI中绘制的所有对象最终都来自公共基类ScreenObject。 我的预览管理器包含对ScreenGrid的单个对象引用,ScreenGrid是整个预览区域的网格对象。

问题#1

我的一些派生屏幕类保留在非托管资源上,例如数据库连接,位图图像和WebBrowser控件。 这些类需要处理这些对象。 我在基本ScreenObject基类中创建了一个虚拟Dispose方法,然后在每个保存非托管资源的派生类中实现了一个覆盖Dispose方法。 但是,现在我刚刚创建了一个名为Dispose的方法,我没有实现IDisposable 。 我应该实现IDisposable吗? 如果是这样,我该如何实现它?

  • 仅在具有非托管资源的派生类上
  • 具有非托管资源的基类和派生类
  • 基类和所有派生类,包括那些没有非托管资源的类

将虚拟Dispose方法放在没有非托管资源的基类中是否错误,以便您可以利用多态?

问题2

在阅读Dispose方法和IDisposable接口时,Microsoft声明处置对象应该只为其父级调用Dispose方法。 父母将为其父母调用它,依此类推。 对我而言,这似乎是倒退。 我可能想要处理一个孩子但保留其父母。

我认为它应该是另一种方式,处置的对象应该处理它的孩子。 然后孩子们应该处理他们的孩子等等。

我在这里错了还是我错过了什么?

问题1:使用以下模式实现IDisposable

 public class MyClass : IDisposable { bool disposed; protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //dispose managed resources } } //dispose unmanaged resources disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } 

问题2:Microsoft的含义是派生类在其父类上调用dispose。 实例的所有者仅在最派生类型上调用Dispose。

一个(缩短的)例子:

 class Parent : IDisposable { protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //dispose managed resources } } //dispose unmanaged resources disposed = true; } } class Child : Parent, IDisposable { protected override void Dispose(bool disposing) { if (!disposed) { if (disposing) { //dispose managed resources } base.Dispose(disposing); } //dispose unmanaged resources disposed = true; } } class Owner:IDisposable { Child child = new Child(); protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { if(child!=null) { child.Dispose(); } } } //dispose unmanaged ressources disposed = true; } } 

所有者只调用Child上的Dispose ,但不调用Parent。 Child负责在Parent上调用Dispose

问题1:

根据您列出的对象类型(即Database,WebBrowser,Bitmap等),就.NET而言,这些只是受资源。 因此,您应该在具有一次性类型作为成员的任何类上实现IDisposable 。 如果它们是本地声明的实例,则只需对它们调用’using()’即可。 虽然你提到的这些实例确实有非托管资源,但是这些实际上是通过.NET从你使用的类型中抽象出来的。 由于您只使用托管类型,因此您应该实现IDisposable 但不使用终结器 。 如果您真的拥有非托管资源作为类成员,则只需要实现终结器。

问题2:

看来你将inheritance(是a)与聚合/包含混淆(有一个)。 例如,如果“Container”包含一次性资源作为类成员,则称为聚合/包含。 因此,在Container的IDisposable实现中调用base.Dispose()与在Container 内部处理一次性资源无关。 您应该记住,如果一个类派生自Container,比如说“DerivedContainer”,那么它 Container的一个实例,尽管有其他成员和/或function。 因此,“DerivedContainer”的任何实例都具有其基类“Container”所具有的所有成员。 如果你从未调用过base.Dispose() ,那么“容器”中的可支配资源将无法正确释放(它实际上是由GC实现的,但是由于许多原因,只是’让.NET处理它’是不好的做法) -请参考我发布的答案, 依赖.NET自动垃圾收集器是不好的做法?

如果你没有调用基类Dispose() ,你最终会得到一个部分处理的对象(放置在派生类中但不在基类中) – 这是一个非常糟糕的场景。 因此调用基类Dispose()非常重要。

我有一个我开发的最佳实践模式(有很多经验和调试内存转储)作为一个例子写在我的博客上。 它展示了如何在基类和派生类上实现IDisposable

http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html

我实现了IDisposable

  class ConnectionConfiguration:IDisposable { private static volatile IConnection _rbMqconnection; private static readonly object ConnectionLock = new object(); public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposing) { return; } if (_rbMqconnection == null) { return; } lock (ConnectionLock) { if (_rbMqconnection == null) { return; } _rbMqconnection?.Dispose();//double check _rbMqconnection = null; } } }