2

我在问,如果一个类 A 继承自 InterfaceA 和 IDisposable,那么 InterfaceA 是否应该从 IDisposable 继承是否是好的/必要的?

4

3 回答 3

2

不。

仅仅因为实现类继承自IDisposable并不意味着它的接口应该实现IDisposable

IDisposable旨在用作类释放非托管资源的一种方式。您的接口很有可能不需要实现类来使用非托管资源,因此没有理由实现实现IDisposable.

于 2013-01-27T06:34:39.617 回答
2

我认为这取决于您的预期用途。例如,如果用户永远不会看到具体的类,而只会看到接口,那么他们就不会期望实现能够实现IDisposable

用户可以执行以下操作:

var disposable = a as IDisposable;
if (disposable != null)
    disposable.Dispose();

但我认为他们中的大多数人不会这样做,除非您的文档明确说明他们应该这样做。

另一方面,如果您希望用户主要直接使用该类,那么他们将知道该类是IDisposable,因此他们可能会正确处理它。

您在评论中提到了 DI 容器。这取决于特定的容器,但我认为大多数 DI 容器会在知道您不再使用该对象时将其丢弃。但这假设容器知道该对象不再使用(在 Castle 的情况下,这很可能意味着调用Release())并且他们不使用“单身生活方式”(在 Castle 术语中)。

于 2013-01-27T12:08:40.143 回答
2

如果最后一个持有对实现并需要清理的对象实例的引用的实体可能只将该实例知道为,而不是其底层类型,则接口IFoo可能应该实现。IDisposableIFooIFoo

例如,IEnumerator<T>implements的原因IDisposable是,虽然只有少数实现需要清理,但实例通常由调用IEnumerable<T>.GetEnumerator(). GetEnumerator()这样的代码通常对要返回的对象的实际类型一无所知;因此,它无法知道返回的对象是否需要清理。由于未能处置确实需要清理的枚举数可能会产生不良后果,因此唯一安全的假设是,如果可能,应清理任何未知类型的枚举数。

虽然非泛型IEnumerator没有实现IDisposable,但这并不意味着它不需要清理。相反,这意味着任何调用的代码都IEnumerable.GetEnumerator()必须检查它返回的对象是否实现IDisposable,如果是,则检查Dispose它。这是相当缓慢和麻烦的。如果IEnumerator实现IDisposable,代码可以简单地调用Dispose类是否需要清理;即使Dispose什么都不做,在一个已知实现的接口上调用一个不做任何事情的例程将比测试一个没有实现的接口浪费更少的时间。

It's important to note that even though very few implementations if IEnumerator require disposal, any code which calls GetEnumerator on unknown implementation of IEnumerable must, for correctness, attempt the cast to IDisposable. The fact that IEnumerable<T>, unlike IEnumerable, implements IDisposable does not add to the obligations of code that calls IEnumerable<T>. Rather, it makes such obligations explicit, and it reduces the cost of complying with them.

于 2013-01-27T19:27:28.903 回答