关于c#:代码契约:我们是否必须在委托方法中冗余地指定Contract.Requires(…)语句?

Code Contracts: Do we have to specify Contract.Requires(…) statements redundantly in delegating methods?

我打算在将来的开发中使用新的.NET 4代码契约功能。这让我怀疑我们是否需要在一系列方法中冗余地指定等价的Contract.Requires(...)语句。

我认为一个代码示例值一千个字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public bool CrushGodzilla(string weapon, int velocity)
    {
        Contract.Requires(weapon != null);

        // long code

        return false;
    }

    public bool CrushGodzilla(string weapon)
    {
        Contract.Requires(weapon != null);   // specify contract requirement here
                                             // as well???

        return this.CrushGodzilla(weapon, int.MaxValue);
    }

对于运行时检查来说,这并不重要,因为我们最终总是要进行需求检查,如果失败,我们将得到一个错误。

但是,当我们在第二次过载中没有在这里指定合同要求时,这是否被认为是不好的做法?

另外,还有编译时检查的特性,可能还有代码契约的设计时检查。在Visual Studio 2010中,它似乎还不适用于C语言,但我认为有些语言(如规范)已经适用。当我们编写代码来调用这种方法时,这些引擎可能会给我们一些提示,而我们当前的参数可以或将是null

所以我想知道这些引擎是否总是会分析一个调用堆栈,直到找到一个具有当前不满足的契约的方法?

此外,我在这里了解了Contract.Requires(...)Contract.Assume(...)之间的区别。我想在这个问题的语境中也应该考虑到这种差异?


我认为最好的做法是在每个公共方法上指定所有合同。合同不仅仅是"什么被检查"——它也是有效的文档。如果您调用了一个方法,但不知道应用了什么契约,那么降低契约失败率就很奇怪了:这将表明您调用的方法中存在错误,而不是方法中存在错误。

注意,如果您在整个项目中使用C 4,您可以考虑使用可选参数和命名参数,以避免出现如此多的重载。当然,如果您需要从一种不支持它们的语言调用代码,这是没有用的。

我强烈怀疑,如果您不在"默认"重载中指定合同,静态检查器(现在可用于VS2010的所有版本)将投诉合同可能失败,并建议将合同添加到中。


Also, there will be the feature of
compile time checking, and possibly
also design time checking of code
contracts. It seems it's not yet available for C# in Visual Studio 2010...

它是可用的,但要使它工作,你必须使用VS2010终极版。

警告:这是有点推测性的,但从我使用它所学到的知识来看,似乎是正确的;

您需要像您所做的那样,手动地通过方法传播约束。

代码契约可以从方法外部看到的唯一信息是您所说的。它可以检查方法内部的假设和断言,但这种分析不会传播。换句话说,CC不能"看穿"您的方法,因此它不会自动知道CrushGodzilla(string)将要求weapon非空。

如果使用静态分析,它将在CrushGodzilla(string)中进行检查,并利用CrushGodzilla(string,int)的外部信息,认识到weapon不能为空,建议您添加一个Requires非空的前提条件。(非传播是指该知识不会用于分析程序的其余部分。)

实际上,我没有找到任何地方可以很好地记录静态分析器的文档,尽管我已经看过了。