如何处理IDisposable

本文关键字:IDisposable 处理 何处理 | 更新日期: 2023-09-27 18:27:50

假设我有这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

如何处理IDisposable

您可以使用:

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

不过,我想说通常使用这种类层次结构是个坏主意;这意味着客户端不能以同样的方式只使用"MyBase的任何实例",因为对于特定类型还有额外的约定。使Base实现IDisposable会更干净,即使少数特定类型实际上并不需要它。

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

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