C# 接口上的保守IDisposable标记

C# 接口上的保守IDisposable标记,c#,.net,design-patterns,idisposable,C#,.net,Design Patterns,Idisposable,在可能需要或不需要处理接口实现的情况下,要求所有实现都必须通过将接口本身标记为IDisposable来处理是一个好主意吗 这将强制此接口的用户始终处理对象,即使某些实现可能不需要这样做。我们的目标显然是确保实现始终是无缝可交换的。另一种选择是让用户自己决定,这似乎更正确,但更难沟通。另一方面,考虑到一个用户只有一个用接口类型声明的符号,要求无条件地处理它似乎更为正确。这一推理是否存在权衡或谬误 如果问题过于依赖于具体情况,我想在教科书存储库(存储库设计模式)的上下文中对其进行分析,其中需要处理大

在可能需要或不需要处理接口实现的情况下,要求所有实现都必须通过将接口本身标记为
IDisposable
来处理是一个好主意吗

这将强制此接口的用户始终处理对象,即使某些实现可能不需要这样做。我们的目标显然是确保实现始终是无缝可交换的。另一种选择是让用户自己决定,这似乎更正确,但更难沟通。另一方面,考虑到一个用户只有一个用接口类型声明的符号,要求无条件地处理它似乎更为正确。这一推理是否存在权衡或谬误


如果问题过于依赖于具体情况,我想在教科书存储库(存储库设计模式)的上下文中对其进行分析,其中需要处理大多数已知的实现。

因此,您公开了一个接口

ISomeInterface
如果要使用此接口触发处置,即要调用
Dispose
,则应实现
IDisposable

ISomeInterface : IDisposable

但是,考虑到泛在<代码> IDISPOLISTION/CODE >的组成必然会导致第三方用户“代码> ISOMealSo界面实现调用<代码>处理< /代码> MysVLE,无论是显式还是在<代码>中使用Bug。

如果您不打算自己调用
Dispose
,请将选择权留给具体的类实现者。只有他们才能决定在特定情况下是否有必要进行处置


现在我可以

除非大多数实现极有可能需要清理,否则不要要求它

我认为在
流的例子中,它“极有可能”

如果这个问题过于依赖于具体情况,我想将其置于教科书存储库(存储库设计模式)的上下文中,其中需要处理大多数已知的实现

如果您正在编写实例化对象并负责其生命周期的库代码,那么理想的方案是处理
IDisposable
,但不要求它,除非大多数实现极有可能需要清理;例如,在对未知对象执行代码时,使用
is
as
。它很少像这样简单,但例如:

IFoo obj = (IFoo)Activator.CreateInstance(unknownType);
using(obj as IDisposable)
{
    // TODO: code
}

在决定
IFoo
是否应该实现
IDisposable
时,关键问题不应该是实现
IFoo
的大部分类型是否需要处理,甚至不是实现
IFoo
的大部分对象实例是否需要处理,而是由返回类型为
IFoo
的工厂方法返回的实例的任何非平凡部分是否需要由该工厂方法的调用方处理

考虑
IEnumerator
。实现它的类中只有一小部分需要处理(这部分可能随着迭代器的引入而显著增加),但绝大多数实例将通过调用工厂方法
IEnumerable.GetEnumerator()
,其返回类型为
IEnumerator
。调用IEnumerable.GetEnumerator()的代码通常不知道返回的对象是否需要处理;对于语义正确性,除非代码知道它使用的
IEnumerable
类型不会返回需要处理的实例,否则为了正确性,它必须尝试将返回的实现强制转换为
IDisposable
,如果结果为非空,则处理它们

当Microsoft实现
IEnumerator
时,他们意识到消费者必须尝试将枚举数强制转换为
IDisposable
的负担远远大于实现者必须实现不做任何事情
Dispose
方法的负担。语义正确性要求使用者对任何实现了
IDisposable
的枚举数调用
Dispose
,并且对已知实现的类型无条件调用do nothing
Dispose
方法要比测试可能实现
IDisposable
的类型更容易、更快,这样做


即使只有1%的IEnumerator实现实现了IDisposable
,但为了语义正确性,绝大多数消费者必须假设其中任何一个都可能实现。拥有
IEnumerable
inherit
IDisposable
不会给消费者带来任何其他情况下他们不会有的义务——这只是让他们更容易履行他们在任何情况下都会有的义务。

最近再次思考了这个问题,我想分享另一条准则/经验法则,如果适用,可能会使决策更容易

还没有人考虑的是用户/实现的比率:

    >P>如果用户多于实现,特别是如果实现都在您的控制之下,那么考虑标记接口<代码> IDISPOSTABLE ,并强制用户始终处置,即使它不是严格必要的。只要这对手头的用例来说是合适的,它很可能会让用户的生活更简单:他们不需要检查是否需要处理,他们会系统地处理。缺点是您必须为那些不需要虚拟
    Dispose
    方法的实现实现虚拟
    方法。除非您有特殊的性能要求,否则此调用是完全可靠的