4

假设我有这 3 个课程。

abstract class MyBase
{
    //some base code here
}

class Foo : MyBase, IDisposable
{
    //got at least a field I should dispose
}

class Bar : MyBase, IDisposable
{
    //got at least a field I should dispose
}

我有几节这样的课。我得到了拥有List<base>. 我怎样才能正确处理所有这些类,而不必测试/强制转换以获得正确的类型然后拥有Dispose

4

2 回答 2

8

那么你可以使用:

foreach (var disposable in list.OfType<IDisposable>())
{
    disposable.Dispose(); 
}

不过,我会说拥有这种类层次结构通常是个坏主意。这意味着客户不能MyBase以相同的方式使用“任何实例”,因为对于特定类型还有额外的合同。Base制作implement会更干净IDisposable,即使一些特定类型实际上并不需要它。

于 2013-08-14T12:38:04.960 回答
4

如果可处置性是基类契约的一部分,为什么不明确说明呢?

abstract class MyBase : IDisposable
{
    //some base code here

    //an abstract "implementation" of the interface
    public abstract void Dispose();
}

这样,您可以确定它的所有后代实际上都是一次性的。您还可以按照以下方式创建集合类而不是通用列表:

class MyBaseCollection : IEnumerable<MyBase>
{
    private List<MyBase> innerCollection;
    ....
    public void DisposeItems()
    {
       // call Dispose on each item here
    }
}

正确处理非托管资源可能非常棘手,并且众所周知难以调试。在具体类上实现 IDisposable 接口时,您应该遵循Dispose 模式

在抽象类本身中,您可以根据要对类层次结构执行的操作来做几件事。

  • 如果所有(或大多数)后代都需要处理逻辑,您可以强制他们使用以下方法实现 Dispose 模式的两种方法:

    public abstract void Dispose();
    public abstract void Dispose(bool disposing);
    

    这样子孙就别无选择,只能实现方法,否则代码无法编译。

  • 如果大多数类不需要处理,但其中一些仍然需要处理,我会在基类中声明虚拟方法:

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

    这个默认实现对于大多数后代来说已经足够好了,那些确实需要处理的人可以随意覆盖它。

  • 此外,由于Dispose()方法的代码几乎总是相同的,您可以实现一个,而将另一个保留为虚拟甚至抽象。

    //should not be overridden
    public virtual void Dispose(){
      Dispose(true);
      GC.SuppressFinalize(this);
    }
    
    //must be overriden
    public abstract void Dispose(bool disposing);
    
于 2013-08-14T12:42:26.743 回答