这个IDisposable实现是否正确?

我永远不会记住实现IDisposable接口的所有规则,因此我尝试提出一个基类来处理所有这些并使IDisposable易于实现。 我只是想听听你的意见,如果这个实现是好的,或者你是否看到我可以改进的东西。 该基类的用户应该从它派生,然后实现两个抽象方法ReleaseManagedResources()ReleaseUnmanagedResources() 。 所以这是代码:

 public abstract class Disposable : IDisposable { private bool _isDisposed; private readonly object _disposeLock = new object(); ///  /// called by users of this class to free managed and unmanaged resources ///  public void Dispose() { DisposeManagedAndUnmanagedResources(); } ///  /// finalizer is called by garbage collector to free unmanaged resources ///  ~Disposable() { //finalizer of derived class will automatically call it's base finalizer DisposeUnmanagedResources(); } private void DisposeManagedAndUnmanagedResources() { lock (_disposeLock) //make thread-safe if (!_isDisposed) { //make sure only called once try { //suppress exceptions ReleaseManagedResources(); ReleaseUnmanagedResources(); } finally { GC.SuppressFinalize(this); //remove from finalization queue since cleaup already done, so it's not necessary the garbage collector to call Finalize() anymore _isDisposed = true; } } } private void DisposeUnmanagedResources() { lock (_disposeLock) //make thread-safe since at least the finalizer runs in a different thread if (!_isDisposed) { //make sure only called once try { //suppress exceptions ReleaseUnmanagedResources(); } finally { _isDisposed = true; } } } protected abstract void ReleaseManagedResources(); protected abstract void ReleaseUnmanagedResources(); } 

您正在终结器中访问托管对象_disposeLock。 到那时它可能已经被垃圾收集了。 不确定这会产生什么影响,因为你只是用它来锁定。

线程安全似乎有点矫枉过正。 我认为您不必担心GC线程和应用程序线程之间的争用。

否则看起来是正确的。

我不能真正评论你的代码的正确性,但我怀疑你是否会在你的inheritance树的基础上找到像它需要的那样灵活的Disposable类。 当你想从你不拥有的东西inheritance时,它将没有多大用处。 我认为IDispoasble是一个接口,因为可以使用它的许多不同的域。 在inheritance层次结构的底部提供具体实现将是……限制。

编辑是的,我误读了关于分离处理托管和非托管资源的部分(仍在第一杯咖啡上)。

然而,锁定几乎肯定不是必需的。 是的,在被动处置期间,代码将在终结器线程上运行,该线程与最初运行的线程不同。 但是,如果以这种方式最终确定对象,则CLR已经确定没有对该对象的现有引用并因此收集它。 所以当时没有其他地方可以召唤你的处置,因此没有理由锁定。

其他几种风格评论。

为什么要使方法抽象化? 通过这样做,您强制派生类实现处理托管和非托管资源的方法,即使它们没有任何处置。 如果你没有任何东西可以处理,那么从这个课程中得出来是没有意义的。 但我认为只有一个或另一个但不是两者都相当普遍。 我会让他们虚拟与抽象。

此外,您可以防止双重处置,但您没有做任何事情警告开发人员他们是双重处置对象。 我意识到MSDN文档说双重处理本质上应该是无操作,但同时在什么情况下这应该是合法的? 一般来说,在处理完对象后访问它是个坏主意。 双重处置需要重新使用被处置的对象并且可能是一个错误(如果在活动处置中没有抑制终止但这也可能发生,但这也是一个坏主意)。 如果我正在实现这个,我会抛出双重处置来警告开发人员他们正在使用一个不正确的对象(在它已经被处理后使用它)。

如果您担心线程安全,那么我将使用轻量级互锁操作而不是重量级锁:

 class MyClass: IDispose { int disposed = 0; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public virtual void Dispose(bool disposing) { if (0 == Thread.InterlockedCompareExchange(ref disposed, 1, 0)) { if (disposing) { // release managed resources here } // release unmanaged resources here } } ~MyClass() { Dispose(false); } }