我该如何继承IDisposable?

时间:2009-12-02 16:52:17

标签: c# inheritance interface idisposable coupling

已更改班级名称以保护无辜的

如果我有一个名为ISomeInterface的接口。我还有继承接口的类,FirstClass和SecondClass。 FirstClass使用必须处理的资源。 SecondClass没有。

所以问题是,我应该从IDisposable继承哪里?以下两个选项似乎都不太理想:

1)让FirstClass继承IDisposable 。然后,任何处理ISomeInterfaces的代码都必须知道是否要处理它们。这闻起来像是与我的紧密联系。

2)让ISomeInterface继承IDisposable 。然后,任何从它继承的类都必须实现IDisposable,即使没有任何东西可以处理。除了注释之外,Dispose方法基本上是空白的。

#2对我来说似乎是正确的选择,但我想知道是否有其他选择。

6 个答案:

答案 0 :(得分:20)

如果抽象实体(接口或抽象类)可能有可能是一次性的,它应该实现它。 Stream,例如本身需要IDisposableIEnumerator<T>也不是......

抽象基类可能更简单,因为您可以使用Dispose()的默认(空)实现,也可以使用终结器/ Dispose(bool)模式,即

void IDisposable.Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) {}
~BaseType() {Dispose(false);}

答案 1 :(得分:3)

如果你知道ISomeInterface的某些实现需要处理,那么接口应该继承IDisposable,即使接口的具体实现没有任何可处理的东西。

例如,在BCL中,IDataReader实现了IDisposable,即使人们可以想象没有需要处理的外部资源的数据读取器实现。

答案 2 :(得分:2)

这取决于你的界面,但我倾向于#2。如果你有两个ISomeInterface的实现,只有一个需要处理,那么你可能需要重构。

通常,当您绑定到接口时,最好让该接口继承IDisposable而不是基类;如果您的接口没有继承IDisposable,则必须强制转换为IDisposable以处置该对象,并且存在InvalidCast的风险......

答案 3 :(得分:2)

如果您希望所有代码一般都处理ISomeInterfaces,那么是的,它们都应该是一次性的。

如果没有,那么创建FirstClass的代码应该处理它:

using (FirstClass foo = new FirstClass()) {
    someObjectThatWantsISomeInterface.Act(foo);
}

否则,你总是可以使用类似这种扩展方法的东西:

public static void DisposeIfPossible(this object o) {
    IDisposable disp = o as IDisposable;
    if (disp != null)
        disp.Dispose();
}

// ...
someObject.DisposeIfPossible(); // extension method on object

我还应该提一下,我更喜欢模板基类方法。我在this blog中纠正了这个问题,正确地建造了一次性物品。

答案 4 :(得分:1)

我的建议是转到根,而不是直接转到具体的类。第2点是根,你是由FirstClass的某种契约驱动的。如果您知道类必须实现某个接口,那么您希望确保他们签署合同的接口继承了IDisposable

答案 5 :(得分:1)

到目前为止所写的所有答案都错过了一个关键点:只有基本类型或基本接口才能实现IDisposable,如果它可能是那些需要基础的代码 - 否则,类实例可能获取实例的所有权,该实例需要在不意识到的情况下进行处理。可能发生这种情况的最常见情况是使用工厂方法;一个主要的例子是IEnumerable<T> / IEnumerator<T>。大多数枚举器不需要清理,但调用IEnumerable<T>.GetEnumerator的代码通常没有特别的理由相信返回的枚举器实际上需要清理,也不相信它不会被清除。让IEnumerator<T>的所有实现实现IDisposable并让所有消费者在返回的枚举器上调用Dispose比让消费者检查返回的类型是否实现{通常更快{1}}如果是,请调用它。

如果预期基类型引用通常仅由不负责清理有问题项的方法使用,则基本类型不需要实现IDisposable。负责清理的代码将知道它处理实现IDisposable的对象是否与基类型有关。