你无法真正"阻止"IDisposable蔓延.有些类需要处理,AutoResetEvent
并且最有效的方法是在Dispose()
方法中执行它以避免终结器的开销.但是必须以某种方式调用此方法,因此在您的示例中,封装或包含IDisposable的类必须处理这些,因此它们也必须是一次性的,等等.避免它的唯一方法是:
避免在可能的情况下使用IDisposable类,在单个位置锁定或等待事件,在单个位置保留昂贵的资源等
只在你需要它们时才创建它们并在它之后处理它们(using
模式)
在某些情况下,可以忽略IDisposable,因为它支持可选的大小写.例如,WaitHandle实现IDisposable以支持命名的Mutex.如果未使用名称,则Dispose方法不执行任何操作.MemoryStream是另一个例子,它不使用系统资源,它的Dispose实现也什么都不做.关于是否使用非托管资源的仔细思考可以是教学性的.因此,可以检查.net库的可用来源或使用反编译器.
你无法真正"阻止"IDisposable蔓延.有些类需要处理,AutoResetEvent
并且最有效的方法是在Dispose()
方法中执行它以避免终结器的开销.但是必须以某种方式调用此方法,因此在您的示例中,封装或包含IDisposable的类必须处理这些,因此它们也必须是一次性的,等等.避免它的唯一方法是:
避免在可能的情况下使用IDisposable类,在单个位置锁定或等待事件,在单个位置保留昂贵的资源等
只在你需要它们时才创建它们并在它之后处理它们(using
模式)
在某些情况下,可以忽略IDisposable,因为它支持可选的大小写.例如,WaitHandle实现IDisposable以支持命名的Mutex.如果未使用名称,则Dispose方法不执行任何操作.MemoryStream是另一个例子,它不使用系统资源,它的Dispose实现也什么都不做.关于是否使用非托管资源的仔细思考可以是教学性的.因此,可以检查.net库的可用来源或使用反编译器.
在正确性方面,如果父对象创建并且基本上拥有现在必须是一次性的子对象,则无法阻止IDisposable通过对象关系传播.在这种情况下,FxCop是正确的,父级必须是IDisposable.
您可以做的是避免将IDisposable添加到对象层次结构中的叶类.这并不总是一件容易的事,但这是一项有趣的练习.从逻辑的角度来看,ShoeLace没有必要是一次性的.除了在这里添加WaitHandle之外,还可以在ShoeLace和WaitHandle之间添加一个关联点.最简单的方法是通过Dictionary实例.
如果您可以通过实际使用WaitHandle的地图将WaitHandle移动到松散的关联中,那么您可以打破此链.
为了防止IDisposable
扩散,您应该尝试在单个方法中封装一次性对象的使用.尝试Shoelace
不同的设计:
class Shoelace { bool tied = false; public void Tie() { using (var waitHandle = new AutoResetEvent(false)) { // you can even pass the disposable to other methods OtherMethod(waitHandle); // or hold it in a field (but FxCop will complain that your class is not disposable), // as long as you take control of its lifecycle _waitHandle = waitHandle; OtherMethodThatUsesTheWaitHandleFromTheField(); } } }
等待句柄的范围仅限于该Tie
方法,并且该类不需要具有一次性字段,因此本身不需要是一次性的.
由于wait句柄是一个实现细节Shoelace
,它不应该以任何方式改变它的公共接口,比如在声明中添加一个新接口.当你不再需要一次性场地时会发生什么,你会删除IDisposable
声明吗?如果你考虑Shoelace
抽象,你很快就会意识到它不应该被基础设施依赖性污染,比如IDisposable
.IDisposable
应该为抽象封装了一个需要确定性清理的资源的类保留; 即,对于可处置性是抽象的一部分的类.