如何处理IDisposable?

4
假设我有以下三个类:
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的情况下适当地处理所有这些类?


1
将来请更加注意你的示例 - 遵循.NET命名约定(foobar => FooBar),使用正确的接口名称(iDisposable => IDisposable),不要尝试使用关键字(base)作为标识符。这些错误不会阻止我们帮助您,但它们是不必要的干扰。 - Jon Skeet
2个回答

8

您可以使用以下方法:

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

我认为,这种类层次结构 一般来说 是个不好的主意;这意味着客户端不能像使用“MyBase的任何实例”那样使用它,因为特定类型有额外的契约。即使只有少数特定类型需要,让Base 实现IDisposable 也是更清晰的。


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模式

在抽象类本身中,您可以根据类层次结构的需求执行多项操作。

  • If all (or most) of the descendants will need disposing logic, you can force them to implement both method of the Dispose pattern using:

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

    This way the descendant has no choice but to implement the methods, otherwise the code does not compile.

  • If most of the classes do not need disposing, but some of them still do, I would declare virtual methods in the base class:

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

    This default implementation will be good enough for most descendants, and those that do need disposing can override it at will.

  • Also, since the code of the Dispose() method is pretty much always the same, you can implement that one, and leave the other as virtual or even abstract.

    //should not be overridden
    public virtual void Dispose(){
      Dispose(true);
      GC.SuppressFinalize(this);
    }
    
    //must be overriden
    public abstract void Dispose(bool disposing);
    

1
@im_a_noob:如果所有(或者大多数)派生类都需要 IDisposable,那么这是一个有效的选项。与 System.IO.Stream 进行比较,并注意 MemoryStream 没有需要释放的内容。 - H H
如果没有那行代码,编译器会报错"'MyBase' does not implement interface member 'System.IDisposable.Dispose()'"。尽管如此,根据情况,"public virtual void Dispose(){}"可能是更好的选择。 - SWeko
1
查找std模式。您需要一个protected virtual void Dispose(bool disposing) {} - H H
1
“Dispose模式” - Matthew Watson
增加了一些关于实现可处理层次结构的解释(和选项)。 - SWeko
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接