2010-03-22 74 views
21

我有一个父类和子类,它们都需要实现IDisposablevirtual(和base.Dispose()?)呼叫应该在哪里起作用?当我刚刚重写Dispose(bool disposing)调用时,感觉真的很奇怪,说我实现了IDisposable而没有明确的Dispose()函数(只是使用继承的函数),但具有其他所有内容。在父类还实现IDisposable时在子类上实现IDisposable

我一直在做(小瞧了不少)什么:

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

} 
+0

[:资源下载](https://msdn.microsoft.com/en-us/library/system.idisposable(V = vs.110).aspx0)具有关于如何实施子类对象的IDisposable建议。 – PeterM 2016-08-18 13:52:58

回答

23

当我刚重写的Dispose(BOOL处置)调用,那感觉真是奇怪,说明我实现IDisposable,而无需显式的Dispose()函数(只是使用继承的函数),但具有其他一切。

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

当您为IDisposable类创建子类时,基类已经为您处理了所有“Dispose pattern”管道。你真的应该做什么,但覆盖protected Dispose(bool)方法,并跟踪您是否已经布置已经(到适当提高ObjectDisposedException。)

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


另外,通常考虑封装IDisposable类而不是子类化它是个好主意。有时候,对一个IDisposable类进行子类化是适当的,但它们很少见。封装通常是更好的选择。

+0

啊,我想我的担心是没有根据的,我已经接近做对了(我想知道我在哪里找到了重新实现终结器的想法......)。是的,一般而言,我发现自己的继承越来越少。 – Tanzelax 2010-03-22 23:31:37

+0

芦苇你的博客是辉煌的......但请注意你的答案在这里数 - 7(1是我的))....人们无法appreaciate这足够..耻辱。 – 2012-05-25 13:13:34

3

这种模式的想法是,你重写虚Dispose方法,调用base.Dispose如果必要的。基类负责处理其余的部分,调用虚拟Dispose方法(从而实现正确的实现)。子类不应该需要,也能实现IDisposable(它是通过继承IDisposable

+1

我想我可以取出显式的':IDisposable',因为它已经继承了那个接口。我想我确实喜欢明确说明“这个班级有一些特殊的处理办法”。感谢您的意见,但。 :) – Tanzelax 2010-03-22 23:36:07

1

子类应该重写虚拟Dispose,对子类进行任何特定的处理,并调用超类'Dispose,它将自行完成工作。

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

+0

我不确定我喜欢在已经膨胀的IDisposable模式中添加更多虚拟/抽象方法的想法... – Tanzelax 2010-03-22 23:36:33

+0

@Tanzelax对于他们自己的,我想。提供的代码对我来说很有用,因为我拥有需要一次性使用的类的层次结构。大多数设置都在顶层类中,每个子类都需要最少的额外代码。 – 2010-03-23 00:51:50

3

为什么当你不需要时会变得复杂?

由于您没有封装任何非托管资源,因此您不需要完成所有这些工作。而且,你的类是内部的,这表明你在你自己的程序集中控制了继承层次结构。

因此,简单明了的方法是:

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好得多,就像你在使用它们使用任何其他一次性;就像上面的代码一样直截了当。

+1

当父类没有(除了从Object继承的普通情况之外)的子类应该有清理终结器的情况下,你能想到任何情况吗?我可以理解添加一个终结器,其工作是抱怨不适当抛弃的对象,但恕我直言,任何需要清理的东西都应该在它自己的可终结类中;我可以考虑* NO *例外。 – supercat 2011-04-16 19:31:51

+0

@supercat:我完全[同意](http://codecrafter.blogspot.com/2010/01/revisiting-idisposable.html)。 – 2011-04-17 01:15:03

0

我总是转向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成员。还请注意对资源进行空值检查,因为您不希望在这些块中出现任何异常。

卢克

相关问题