在IDisposable模式中,基类应该允许派生类共享其已处置的标志吗?

时间:2009-07-03 15:03:15

标签: c# .net idisposable

我目前正在修复一个c#代码库,它没有良好的Dispose使用模式。

这是一个庞大的代码库,它是一个需要资源的代码库,它在低级别使用了许多自定义的非托管c ++库。

我对处理模式有很好的理解。我花了一些时间来理解我认为是关于这个问题的黄金标准文章:Joe Duffy's dispose article

为了尽量减少代码重复,我们一直在考虑一些dispose帮助程序类,所以我的问题是:

如果基类实现了标准的Dispose模式,它应该允许共享其置位标志,即。标记为受保护?

澄清我的意思是,在继承层次结构中是否只有一个布尔状态,它定义了对象实例是否已被处理,或者在继承阶梯的每一步都应该有一个私有布尔值?

MSDN和上述链接中的示例在每个级别设置了一个标志,但从不解释其背后的原因。我对这个问题有两个想法,你有什么想法和理由?

4 个答案:

答案 0 :(得分:5)

我会说不,它不应该分享旗帜。共享标志会创建失败的机会,更好的封装可以防止这种失败。

例如,考虑在最基类上具有只读Disposed属性的场景。支持字段仅在基类的Dispose(disposing)方法中设置为true。这意味着,如果调用基类Dispose,则属性Disposed只能返回true(当然除非有恶意反映)。这允许基类提供可执行的合同。

现在考虑相反的情况,其中有一个受保护的setter。任何类现在都可以任意设置Disposed属性为true而不进行任何处理。这为Dispose提供了在没有任何处理时返回true的机会。

我会选择第一个选项,因为它提供了最强制执行的合同。

答案 1 :(得分:0)

我建议在基类上使用公共getter和受保护的setter来设置Disposed属性。

答案 2 :(得分:0)

如果你有方法在处理类时应该做一些不同的事情,例如抛出异常,我会为基类创建一个受保护的getter属性,读取基类上的私有字段。这样,您可以允许任何继承者知道他是否能够执行操作。

然后,为了知道某个类是否已经被置于其自己的dispose方法中(例如:为了避免两次释放资源),我认为拥有私有标志对于清晰度和维护更好。

答案 3 :(得分:0)

除了JaredPar的回答之外,我还要补充说,并不总是需要_disposed标志。通常,对象的其他“资源相关”字段自然地提供表示处置状态的方式。

例如,在丢弃之前需要Shutdown的外部COM对象将由对COM对象的引用表示,因此Dispose的相关部分将是:

if (_comObject != null)
{
    _comObject.Shutdown();
    _comObject = null;
}

根据需要,可以安全地多次运行,而无需多次调用Shutdown。尝试在Dispose之后使用_comObject的其他方法将获得NullReferenceException,或者理想情况下这些方法将检查_comObject字段并抛出ObjectDisposedException

我发现这通常不是真的 - 经常实现IDisposable,我不记得曾经需要一个单独的_disposed字段。引入一个会增加自由度(增加让我搞砸的方式)。

所以这对于派生类来说不太可能有用,即使它是一个安全的想法(正如JaredPar所解释的那样)。