22

类名已更改以保护无辜者

如果我有一个名为 ISomeInterface 的接口。我也有继承接口的类,FirstClass 和 SecondClass。FirstClass 使用必须释放的资源。二等舱没有。

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

1)使 FirstClass 继承 IDisposable。然后,任何处理 ISomeInterfaces 的代码都必须知道是否要处理它们。这对我来说就像紧耦合。

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

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

4

6 回答 6

19

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

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

~BaseType() => Dispose(false);

protected virtual void Dispose(bool disposing) 
{
}

void IDisposable.Dispose() 
{ 
    Dispose(true); GC.SuppressFinalize(this); 
}
于 2009-12-02T16:55:08.523 回答
3

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

例如,在 BCL 中,IDataReader 实现了 IDisposable,尽管我们当然可以想象数据读取器实现不需要需要处理的外部资源。

于 2009-12-02T16:56:09.040 回答
2

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

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

于 2009-12-02T16:57:32.950 回答
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

我还应该提到,我更喜欢模板基类方法。我在这篇关于正确构建一次性物品的博客中对此进行了讨论。

于 2009-12-02T17:00:29.683 回答
2

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

如果预计基类型引用通常仅由不负责清理相关项目的方法使用,则无需实现基类型IDisposable。负责清理的代码将知道它正在处理的对象IDisposable是否实现了基类型。

于 2012-09-27T20:59:52.983 回答
1

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

于 2009-12-02T16:56:18.367 回答