请参阅代码合同手册。它肯定会告诉你所有你需要知道的关于各种形式的代码契约检查是如何工作的,以及在使用每种形式时需要设置哪些选项。
Contract.Requires(bool cond)
和有什么区别Contract.Requires<TException>(bool cond)
?
要回答您的第一个问题,请参阅手册中的第2.1 节前提条件。简而言之,这里有区别:
Contract.Requires(bool cond)
Contract.ContractException
如果条件评估为 ,这将引发私有异常false
。你不能捕捉到这个异常(因为从你的角度来看它是私有的)——这是为了阻止捕捉和处理它,从而使合同变得毫无价值。
Contract.Requires<TException>(bool cond)
如果条件评估为false
,TException
则将抛出指定的。如果不对所有构建运行合约工具,您就无法使用此表单。
关于ccrewrite
具体来说,在第 20 页的第5 节使用指南中,它告诉您代码合同可以使用的所有不同形式的合同、它们如何工作以及每种合同的构建要求是什么。
我将简要总结一下,但请下载手册并阅读。它非常好,虽然不完整——你必须做很多实验来学习如何有效地使用代码契约。此外,如果您可以访问 PluralSight,John Sonmez 有一门名为Code Contracts的课程,这是一门很棒的入门课程;Michael Perry 有一门很棒的课程,叫做Provable Code。
发布的代码不需要合同检查
如果您不需要在已发布的代码中进行合同检查,那么:
Contract.Requires
随处使用
- 仅在调试版本上启用运行时检查。
发布代码需要代码契约检查
如果您需要对已发布代码进行合同检查,您有两种选择:
- 使用代码合同“本机”前提条件:
- 用于您想要抛出特定异常
Contract.Requires<TException>
的公共API 方法(例如,将由您的库的用户调用的方法),例如ArgumentException
.
- 用于
Contract.Requires
您不想为其抛出特定异常的非公共API 方法或 公共API 方法。
- 对所有构建启用运行时检查。
- 确保您启用仅在程序集的公共表面区域发出前置条件的选项-例如,仅那些可由您的库使用者调用的方法。
- 使用“遗留”合同检查:
- 这是您的公共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构建上运行。