"Contract.Requires<T>" 在没有 ccrewrite 的情况下表现如何?这与 "Requires" 有区别吗?
How does "Contract.Requires<T>" behave without ccrewrite? Does this differ from "Requires"?
当未使用 ccrewrite(假设该项目是由另一位未安装 CC 的开发人员构建的),
Contract.Requires<T>(cond)
是被悄无声息地剥离还是仍然导致等同于 if (!cond) { throw new T() }
的行为? (我不在乎它是不是另一个或两个方法调用 - 但它应该 "always be checked"。)
我问是因为 Contract.Requires<T>
的行为似乎与 Contract.Requires
不同,但我不确定 "how" 或 "when"。
目标是替换公共合同
的结构
if (x != null) throw new ArgumentNullException();
使用 CC 兼容版本,在构建步骤期间不执行 CC 重写时仍会抛出异常。
虽然上面的 EndContractBlock
确实适用于 "Custom Parameter Validation"(即遗留合同模式),但我想在项目中使用 "Standard Contract Requires"。
我相信可能是等价的,因为在"Custom Parameter Validation"模式下我无法使用Requires<T>
;如果没有等同于始终需要的检查,那么了解为什么会很好。
当 CC 重写没有完成时,我很好地失去了 Requires
、Ensures
并留在了非尊重的不变契约方法和接口契约中,因为我重视它们用于静态分析 - 但是我需要这些始终存在的边界检查来支持保持 CC。
请参阅Code Contracts manual。它肯定会告诉您所有您需要了解的各种形式的代码合同检查如何工作以及在使用每种形式时需要设置哪些选项。
Contract.Requires(bool cond)
和 Contract.Requires<TException>(bool cond)
有什么区别?
要回答您的第一个问题,请参阅手册中的 2.1 先决条件 部分。简而言之,区别如下:
Contract.Requires(bool cond)
如果条件的计算结果为 false
,这将抛出私有 Contract.ContractException
异常。您无法捕获此异常(因为从您的角度来看它是私有的)——这是为了阻止捕获和处理它,从而使合同变得毫无价值。
Contract.Requires<TException>(bool cond)
如果条件计算为 false
,将抛出指定的 TException
。 运行在所有构建上启用合同工具,您无法使用此表格。
关于ccrewrite
具体来说,第 20 页,第 5 节。使用指南,它告诉您代码合同可以使用的所有不同形式的合同、它们如何工作以及每种合同的构建要求是什么。
我会简要总结一下,但请下载手册并阅读。它非常好,尽管在任何方面都不完整——您必须进行大量实验才能学习如何有效地使用代码契约。此外,如果您可以访问 PluralSight,John Sonmez 有一门名为 Code Contracts which is a great introductory course; and Michael Perry has an awesome course called Provable Code.
的课程
已发布的代码不需要合同检查
如果您不需要在已发布的代码中检查合同,则:
- 到处使用
Contract.Requires
- 启用 运行时检查仅调试构建.
已发布代码需要代码契约检查
如果您需要对发布的代码进行合同检查,您有两种选择:
- 使用代码契约"native"前提条件:
- 在 public API 方法上使用
Contract.Requires<TException>
(例如将调用的方法由你的图书馆的用户)你想抛出特定的异常,例如ArgumentException
.
- 将
Contract.Requires
用于非publicAPI方法 或 public API 方法你不想抛出特定的异常.
- 启用运行时检查在所有构建.
- 确保你启用选项只发出先决条件和仅在组件的 public 表面积 上——例如仅那些可由您的库使用者调用的方法。
- 使用"legacy"合同检查:
- 这是你的老派风格
if (cond) { throw new Exception(...) }
你的 public API 方法 的保护块
- 使用手动继承在派生类型上执行契约。 (当使用选项 1 时,代码合约可以从基 类 自动继承合约,帮助您避免违反里氏替换原则。)
- 确保将行
Contracts.EndContractBlock()
放在所有 if (cond) { throw new Exception(...) }
块之后,以便代码合同知道这些是您的合同。
- 关于非publicAPI方法,大家可以放心使用
Contract.Requires
为您的合同。
- 启用运行时检查仅在调试版本.
关于上述内容需要注意的一件事:在 Debug 构建中 始终 启用合同检查。如果您团队中的其他开发人员将构建此库,他们还需要安装代码合同。
来自第 5.1.3 节:强制项目使用合同构建:
If you are using scenario 2 (Requires〈Exn〉) and you make your source code available to other developers, you might want to alert them that they need to use the tools to build your source. If so, you can insert the following snippet into your project file at the end (after the import of CSharp or VisualBasic targets):
<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
) always 运行 on Debug builds.
当未使用 ccrewrite(假设该项目是由另一位未安装 CC 的开发人员构建的),
Contract.Requires<T>(cond)
是被悄无声息地剥离还是仍然导致等同于 if (!cond) { throw new T() }
的行为? (我不在乎它是不是另一个或两个方法调用 - 但它应该 "always be checked"。)
我问是因为 Contract.Requires<T>
的行为似乎与 Contract.Requires
不同,但我不确定 "how" 或 "when"。
目标是替换公共合同
的结构if (x != null) throw new ArgumentNullException();
使用 CC 兼容版本,在构建步骤期间不执行 CC 重写时仍会抛出异常。
虽然上面的 EndContractBlock
确实适用于 "Custom Parameter Validation"(即遗留合同模式),但我想在项目中使用 "Standard Contract Requires"。
我相信可能是等价的,因为在"Custom Parameter Validation"模式下我无法使用Requires<T>
;如果没有等同于始终需要的检查,那么了解为什么会很好。
当 CC 重写没有完成时,我很好地失去了 Requires
、Ensures
并留在了非尊重的不变契约方法和接口契约中,因为我重视它们用于静态分析 - 但是我需要这些始终存在的边界检查来支持保持 CC。
请参阅Code Contracts manual。它肯定会告诉您所有您需要了解的各种形式的代码合同检查如何工作以及在使用每种形式时需要设置哪些选项。
Contract.Requires(bool cond)
和 Contract.Requires<TException>(bool cond)
有什么区别?
要回答您的第一个问题,请参阅手册中的 2.1 先决条件 部分。简而言之,区别如下:
Contract.Requires(bool cond)
如果条件的计算结果为 false
,这将抛出私有 Contract.ContractException
异常。您无法捕获此异常(因为从您的角度来看它是私有的)——这是为了阻止捕获和处理它,从而使合同变得毫无价值。
Contract.Requires<TException>(bool cond)
如果条件计算为 false
,将抛出指定的 TException
。 运行在所有构建上启用合同工具,您无法使用此表格。
关于ccrewrite
具体来说,第 20 页,第 5 节。使用指南,它告诉您代码合同可以使用的所有不同形式的合同、它们如何工作以及每种合同的构建要求是什么。
我会简要总结一下,但请下载手册并阅读。它非常好,尽管在任何方面都不完整——您必须进行大量实验才能学习如何有效地使用代码契约。此外,如果您可以访问 PluralSight,John Sonmez 有一门名为 Code Contracts which is a great introductory course; and Michael Perry has an awesome course called Provable Code.
的课程已发布的代码不需要合同检查
如果您不需要在已发布的代码中检查合同,则:
- 到处使用
Contract.Requires
- 启用 运行时检查仅调试构建.
已发布代码需要代码契约检查
如果您需要对发布的代码进行合同检查,您有两种选择:
- 使用代码契约"native"前提条件:
- 在 public API 方法上使用
Contract.Requires<TException>
(例如将调用的方法由你的图书馆的用户)你想抛出特定的异常,例如ArgumentException
. - 将
Contract.Requires
用于非publicAPI方法 或 public API 方法你不想抛出特定的异常. - 启用运行时检查在所有构建.
- 确保你启用选项只发出先决条件和仅在组件的 public 表面积 上——例如仅那些可由您的库使用者调用的方法。
- 在 public API 方法上使用
- 使用"legacy"合同检查:
- 这是你的老派风格
if (cond) { throw new Exception(...) }
你的 public API 方法 的保护块
- 使用手动继承在派生类型上执行契约。 (当使用选项 1 时,代码合约可以从基 类 自动继承合约,帮助您避免违反里氏替换原则。)
- 确保将行
Contracts.EndContractBlock()
放在所有if (cond) { throw new Exception(...) }
块之后,以便代码合同知道这些是您的合同。 - 关于非publicAPI方法,大家可以放心使用
Contract.Requires
为您的合同。 - 启用运行时检查仅在调试版本.
- 这是你的老派风格
关于上述内容需要注意的一件事:在 Debug 构建中 始终 启用合同检查。如果您团队中的其他开发人员将构建此库,他们还需要安装代码合同。
来自第 5.1.3 节:强制项目使用合同构建:
If you are using scenario 2 (Requires〈Exn〉) and you make your source code available to other developers, you might want to alert them that they need to use the tools to build your source. If so, you can insert the following snippet into your project file at the end (after the import of CSharp or VisualBasic targets):
<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
) always 运行 on Debug builds.