【问题标题】:Implementing IDisposable on a subclass when the parent also implements IDisposable当父类也实现 IDisposable 时在子类上实现 IDisposable
【发布时间】:2011-01-30 13:53:14
【问题描述】:

我有一个父类和子类都需要实现IDisposablevirtual(和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);
    }

}

【问题讨论】:

  • Msdn 提供了有关如何对实现 IDisposable 的对象进行子类化的建议。

标签: c# .net inheritance idisposable


【解决方案1】:

这种模式的想法是覆盖虚拟的Dispose 方法,必要时调用base.Dispose。基类负责其余的工作,调用虚拟的 Dispose 方法(以及正确的实现)。子类应该不需要也实现IDisposable(通过继承是IDisposable

【讨论】:

  • 我想我可以去掉显式的: IDisposable,因为它已经继承了那个接口。我想我确实喜欢明确指出“这个类有一些特殊的处理发生”。不过,感谢您的输入。 :)
【解决方案2】:

当我只是重写 Dispose(bool disposing) 调用时,感觉很奇怪,说我实现 IDisposable 时没有显式的 Dispose() 函数(只是利用继承的函数),而是拥有其他所有功能。

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

当您对 IDisposable 类进行子类化时,基类已经为您处理了所有“Dispose 模式”管道。除了重写 protected Dispose(bool) 方法之外,您真的应该什么都不做,并跟踪您是否已经被处置(以正确提高 ObjectDisposedException。)

有关详细信息,请参阅我在 Subclassing from an IDisposable class 上的博客文章。


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

【讨论】:

  • 啊,我想我的担心是没有根据的,而且我已经接近正确了(我想知道我从哪里获得了重新实现终结器的想法......哦,好吧)。是的,总的来说,我发现自己使用的继承越来越少。
  • Reed 你的博客很棒......但请注意你的答案的数量 - 7(1 是我的 :))......人们无法充分理解这一点......耻辱。
【解决方案3】:

子类应覆盖虚拟 Dispose,执行特定于子类的任何处理,并调用超类的 Dispose,后者将依次完成自己的工作。

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

【讨论】:

  • 我不确定我是否喜欢向已经臃肿的 IDisposable 模式添加更多虚拟/抽象方法的想法......
  • @Tanzelax 对于每个人来说,我想。提供的代码对我很有用,因为我有一个需要一次性使用的类层次结构。大多数设置都在顶级类中,每个子类只需要最少的额外代码。
【解决方案4】:

当你不需要的时候为什么要把事情复杂化?

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

因此,直截了当的方法是:

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(); 
  } 
} 

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

【讨论】:

  • 你能想到在父类没有的情况下子类应该有一个清理终结器(除了从 Object 继承的小例子)吗?我可以理解添加一个终结器,其工作是抱怨不正确地放弃的对象,但恕我直言,任何需要清理的东西都应该在它自己的终结类中;我能想到NO个例外。
  • @supercat:我完全是agree
  • 您应该阻止它们覆盖公共的 Dispose 方法,而是覆盖受保护的方法。见:docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
  • 嘿@DavidAnderson,没有受保护的方法,因为我没有故意遵循 Microsoft 的一次性用品模式。看看我的方法herehere
【解决方案5】:

我总是求助于 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

请注意,子类有自己的 _isDisposed 成员。还要注意对资源进行空值检查,因为您不希望这些块中有任何异常。

卢克

【讨论】:

    猜你喜欢
    • 2011-05-25
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    相关资源
    最近更新 更多