当父类也实现 IDisposable 时,在子类上实现 IDisposable

问题描述 投票:0回答:6

我有一个父类和子类都需要实现

IDisposable
virtual
(和
base.Dispose()
?)调用应该在哪里发挥作用?当我只是重写
Dispose(bool disposing)
调用时,感觉非常奇怪,因为我实现了
IDisposable
,而没有显式
Dispose()
函数(仅利用继承的函数),但拥有其他一切。

我一直在做什么(有点琐碎):

internal class FooBase : IDisposable
{
    Socket baseSocket;

    private void SendNormalShutdown() { }

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

    private bool _disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                SendNormalShutdown();
            }
            baseSocket.Close();
        }
    }

    ~FooBase()
    {
        Dispose(false);
    }
}

internal class Foo : FooBase, IDisposable
{
    Socket extraSocket;

    private bool _disposed = false;
    protected override void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            extraSocket.Close();
        }
        base.Dispose(disposing);
    }

    ~Foo()
    {
        Dispose(false);
    }

}
c# .net inheritance idisposable
6个回答
33
投票

当我只是重写 Dispose(bool dispose) 调用时,感觉非常奇怪,因为我实现了 IDisposable 而没有显式的 Dispose() 函数(仅利用继承的函数),但拥有其他一切。

这是你不应该关心的事情。

当您对 IDisposable 类进行子类化时,基类已经为您处理了所有“Dispose 模式”管道。你真的不应该做任何事情,除了重写

protected Dispose(bool)
方法,并跟踪你是否已经被处理(以正确地引发
ObjectDisposedException
。)

有关详细信息,请参阅我的博客文章 从 IDisposable 类进行子类化


此外,通常最好考虑封装 IDisposable 类而不是对其进行子类化。有时,对 IDisposable 类进行子类化是合适的,但这种情况很少见。封装通常是更好的选择。


7
投票

我总是求助于 Joe Duffy 对这种模式的非常深入的研究。对我来说,他的版本就是福音。

http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/

首先要记住的是,大多数时候不需要终结器。它用于清除直接持有本机资源的非托管资源,即仅没有自己的终结器的资源。

这是基类子类对的示例。

// Base class

    #region IDisposable Members

    private bool _isDisposed;

    public void Dispose()
    {
        this.Dispose(true);
        // GC.SuppressFinalize(this); // Call after Dispose; only use if there is a finalizer.
    }

    protected virtual void Dispose(bool isDisposing)
    {
        if (!_isDisposed)
        {
            if (isDisposing)
            {
                // Clear down managed resources.

                if (this.Database != null)
                    this.Database.Dispose();
            }

            _isDisposed = true;
        }
    }

    #endregion


// Subclass

    #region IDisposable Members

    private bool _isDisposed;

    protected override void Dispose(bool isDisposing)
    {
        if (!_isDisposed)
        {
            if (isDisposing)
            {
                // Clear down managed resources.

                if (this.Resource != null)
                    this.Resource.Dispose();
            }

            _isDisposed = true;
        }

        base.Dispose(isDisposing);
    }

    #endregion

注意子类有自己的_isDispose成员。另请注意对资源的空检查,因为您不希望这些块中出现任何异常。

卢克


5
投票

为什么在不需要的时候让事情变得复杂?

由于您没有封装任何非托管资源,因此您不需要对终结进行所有处理。而且,您的类是内部的,这表明您可以在自己的程序集中控制继承层次结构。

因此,直接的方法是:

internal class FooBase : IDisposable 
{ 
  Socket baseSocket; 

  private void SendNormalShutdown() 
  { 
    // ...
  } 

  private bool _disposed = false; 

  public virtual void Dispose() 
  { 
    if (!_disposed)
    { 
      SendNormalShutdown(); 
      baseSocket.Close(); 
      _disposed = true;
    } 
  } 
} 

internal class Foo : FooBase
{ 
  Socket extraSocket; 

  private bool _disposed = false; 

  public override void Dispose()
  { 
    if (!_disposed)
    { 
      extraSocket.Close(); 
      _disposed = true;
    } 

    base.Dispose(); 
  } 
} 

即使您确实拥有非托管资源,我想说您最好将它们封装在自己的一次性类中,并像使用任何其他一次性资源一样使用它们;就像上面的代码一样简单。


4
投票
此模式的想法是重写虚拟

Dispose

 方法,并在必要时调用 
base.Dispose
。基类负责其余的工作,调用虚拟 Dispose 方法(从而实现正确的实现)。子类不需要也实现
IDisposable
(它是通过继承实现
IDisposable


2
投票
子类应该重写虚拟 Dispose,执行特定于子类的任何处理,并调用超类的 Dispose,而超类又将执行自己的工作。

编辑:

http://davybrion.com/blog/2008/06/dispose-of-the-idisposable-implementation/是我在这种情况下遵循的模式。不是专门的“Disposable”类,而是继承和覆盖。


0
投票
微软官方对此的指南:

https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern-for-a-衍生类

© www.soinside.com 2019 - 2024. All rights reserved.