如何强制一个不变的方法在C#代码契约中抛出一个特殊的异常?

时间:2013-12-22 10:46:43

标签: c# exception code-contracts throw invariants

我希望我的对象不变方法抛出一个特定的异常。是否有意义?在C#中有可能吗?

例如,我有以下代码,包括具有不变方法的A类和异常类E.现在E类没有参与A ...

class A {
    int x = 0, y = 1;

    [ContractInvariantMethod]
    private void YisGreaterThanX() {
        Contract.Invariant(x < y);
    }
}

class E : Exception {
}

我需要的是以下内容。像Contract.Requires一样,拥有Contract.Invariant(或者可能是一个接受Exception派生类的属性构造函数)会很有用。

class A {
    int x = 0, y = 1;

    [ContractInvariantMethod]
    private void YisGreaterThanX() {
        Contract.Invariant<E>(x < y);
    }
}

class E : Exception {
}

这是一个好意吗?可能是我的逻辑错了?

1 个答案:

答案 0 :(得分:0)

鉴于我们不应该是catching Contract failures,并且因为没有明确指定异常的overload for Contract.Invariant,所以这个答案是有希望的假设。

因此,在所有免责声明之后,你可以通过连接一个ContractFailed事件处理程序来破解以下几行:

Contract.ContractFailed += Contract_ContractFailed();

在处理程序中,过滤Invariant个失败,并处理失败并重新抛出异常:

public static void Contract_ContractFailed(object sender,  ContractFailedEventArgs e)
{
    if (e.FailureKind == ContractFailureKind.Invariant)
    {
        e.SetHandled();
        throw new E(e.Message, e.OriginalException);
    }
}

鉴于您无法在Contract.Invariant定义中传递太多信息,如果您需要参数化抛出的异常,则需要将预期的异常编码为例如ContractFailedbool, string Contract.Invariant overload,或使用外部全局状态,例如线程本地存储。

所有这些都是臭臭的IMO。所以为了回答你的上一个问题,我认为抛出可捕获的异常根本不是一个好主意 - 你的代码被调用超出其设计的状态范围,因此在某处缺少错误/验证。

修改
随后注意到ContractException处理程序中的处理+抛出仍然包含在内部catch(Exception ex) { var myException = ex.InnerException; // ... do something } 中。所以你需要解压缩,例如

{{1}}