3

使用 ccrewrite时(假设项目是由另一个未安装 CC 的开发人员构建的),

Contract.Requires<T>(cond)默默地被剥离还是仍然导致等同于的行为if (!cond) { throw new T() }?(我不在乎它是否是另一个或两个方法调用 - 但它应该“总是被检查”。)

我问是因为Contract.Requires<T>看起来与 的行为不同Contract.Requires,但我不确定“如何”或“何时”。

目标是取代公共合同的结构

if (x != null) throw new ArgumentNullException();

与 CC 兼容的版本在构建步骤期间不执行 CC 重写时仍会引发异常。

虽然上述EndContractBlock与“自定义参数验证”(即遗留合同模式)一起使用,但我想在项目中使用“标准合同要求”。

我相信可能存在等效性,因为在“自定义参数验证”模式下我无法使用Requires<T>;如果没有与始终需要的检查等效的内容,那么了解为什么会很好。

当 CC 重写未完成时,我很好地丢失了Requires, Ensures,并留下了非兑现的不变契约方法和接口契约,因为我重视它们以进行静态分析 - 但我需要这些始终存在的边界检查来争论保留 CC。

4

1 回答 1

4

请参阅代码合同手册。它肯定会告诉你所有你需要知道的关于各种形式的代码契约检查是如何工作的,以及在使用每种形式时需要设置哪些选项。

Contract.Requires(bool cond)和有什么区别Contract.Requires<TException>(bool cond)

要回答您的第一个问题,请参阅手册中的第2.1 节前提条件。简而言之,这里有区别:

Contract.Requires(bool cond)

Contract.ContractException如果条件评估为 ,这将引发私有异常false。你不能捕捉到这个异常(因为从你的角度来看它是私有的)——这是为了阻止捕捉和处理它,从而使合同变得毫无价值。

Contract.Requires<TException>(bool cond)

如果条件评估为falseTException则将抛出指定的。如果不对所有构建运行合约工具,您就无法使用此表单。

关于ccrewrite

具体来说,在第 20 页的第5 节使用指南中,它告诉您代码合同可以使用的所有不同形式的合同、它们如何工作以及每种合同的构建要求是什么。

我将简要总结一下,但请下载手册并阅读。它非常好,虽然不完整——你必须做很多实验来学习如何有效地使用代码契约。此外,如果您可以访问 PluralSight,John Sonmez 有一门名为Code Contracts的课程,这是一门很棒的入门课程;Michael Perry 有一门很棒的课程,叫做Provable Code

发布的代码不需要合同检查

如果您不需要在已发布的代码中进行合同检查,那么:

  • Contract.Requires随处使用
  • 仅在调试版本上启用运行时检查。

发布代码需要代码契约检查

如果您需要对已发布代码进行合同检查,您有两种选择:

  1. 使用代码合同“本机”前提条件:
    • 用于您想要抛出特定异常Contract.Requires<TException>公共API 方法(例如,将由您的库的用户调用的方法),例如ArgumentException.
    • 用于Contract.Requires不想为其抛出特定异常的非公共API 方法 公共API 方法。
    • 所有构建启用运行时检查。
    • 确保您启用仅在程序集的公共表面区域发出前置条件的选项-例如,仅那些可由您的库使用者调用的方法。
  2. 使用“遗留”合同检查:
    • 这是您的公共API 方法上的旧式if (cond) { throw new Exception(...) }保护块
    • 使用手动继承对派生类型强制执行契约。(使用选项 1 时,代码契约可以从基类执行契约的自动继承,帮助您避免违反里氏替换原则。)
    • 确保Contracts.EndContractBlock()在所有if (cond) { throw new Exception(...) }块之后放置该行,以便代码合同知道这些是您的合同。
    • 非公共API 方法上,您可以随意使用Contract.Requires您的合约。
    • 仅在调试版本上启用运行时检查。

关于上述内容需要注意的一件事:在调试版本上始终启用合同检查。如果您团队中的其他开发人员将构建此库,他们还需要安装代码合同。

第 5.1.3 节:强制项目使用合同构建

如果您正在使用场景 2(Requires⟨Exn⟩)并且您将源代码提供给其他开发人员,您可能希望提醒他们他们需要使用这些工具来构建您的源代码。如果是这样,您可以在最后(在导入 CSharp 或 VisualBasic 目标之后)将以下代码段插入到您的项目文件中:

<PropertyGroup>
<CompileDependsOn>$(CompileDependsOn);CheckForCodeContracts</CompileDependsOn>
</PropertyGroup>
<Target Name="CheckForCodeContracts"
        Condition="'$(CodeContractsImported)' != 'true'">
  <Error Text="Project requires Code Contracts: http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx" />
</Target>

此外,请参阅第 6.1 节:装配模式,其中告诉您自定义参数验证标准合同要求之间的区别。本节清楚地表明合约重写器 ( ccrewrite)始终Debug构建上运行。

于 2016-02-20T19:49:52.930 回答