使用不变式(invariant)来处理IDisposable

6

Consider the following IDisposable class:

class MyClass : IDisposable
{
    public bool IsDisposed { get; private set; } = false;

    public void Dispose()
    {
        IsDisposed = true;
    }
}

这个类中的每个方法,包括Dispose(),都应该以以下方式开始检查:

if (IsDisposed)
{
    throw new ObjectDisposedException(...);
}

由于在所有方法中编写此内容很繁琐且重复,因此我希望使用合同不变式:

public class MyClass : IDisposable
{
    ...

    [ContractInvariantMethod]
    private void objectInvariant()
    {
        Contract.Invariant(!IsDisposed)
    }

    ...
}

然而,这仅确保在每个公共方法结束时IsDisposed为false(不包括Dispose())。
一旦调用Dispose(),应在每个方法的开头(包括Dispose())进行检查。否则,在方法运行期间,对象将处于无效状态,可能导致难以调试的错误。
因此,契约不变量对于IDisposable并不真正可用。或者我有所遗漏?
是否可以强制不变量也用作前置条件,还是我真的必须手动向所有方法编写相同的前置条件(!IsDisposed)?

4
这个类中的每个方法,包括Dispose(),都应该以这样的检查开始。"Dispose"方法通常应该能够被多次调用而不会抛出异常,因此不应包含此检查。此外,通常只在对象被处理后不能使用的成员中执行此检查 - 其他成员不需要进行检查。 - Joe
看看这个问题吧,我认为它可能会有帮助。https://dev59.com/xmox5IYBdhLWcg3weUCe 这个问题是关于如何在调用类中的任何方法之前调用一个方法。也许这个答案https://dev59.com/xmox5IYBdhLWcg3weUCe#9192747 - M.kazem Akhgary
1个回答

4
您好,您似乎对不变量存在误解。根据文档:
对象不变量是应该对每个类实例“在该对象对客户端可见时”都为真的条件。
(强调我的)
当您调用Dispose后,您的对象仍然可能对客户端可见,从而使对象“无效”。但是,对于您的对象来说,具有IsDisposed == true实际上是有效状态。
您真正寻找的是前置条件。

我明白了。我基本上是在寻找一种避免将相同的前置条件放到每个方法和属性中的方法。 - Libor
1
这将是一个AOP库(如PostSharp)的任务。您还可以使用LinFu创建动态拦截器。 - Daniel Hilgarth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接