“Contract.Requires <t>”如何在没有ccrewrite的情况下运行?这与“需要”有什么不同?</t>

时间:2015-01-07 17:23:06

标签: c# exception runtime code-contracts ccrewrite

使用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>;如果总是要求检查没有等效性,那就明白为什么会很好。

我很好地失去了RequiresEnsures,并且在没有进行CC重写的情况下留下了非荣誉的不变合约方法和接口合约,因为我重视静态分析 - 但我需要这些总是有边界检查来争取保持CC。

1 个答案:

答案 0 :(得分:3)

请参阅Code Contracts manual。它肯定会告诉您有关各种形式的代码合同检查的工作原理以及使用每个表单时需要设置的选项。

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的课程,这是一个很棒的入门课程;迈克尔佩里有一个很棒的课程叫做Provable Code

发布代码不需要合同检查

如果您不需要在已发布的代码中签订合同,那么:

  • 到处使用Contract.Requires
  • 启用 运行时检查仅限调试构建

已发布代码需要代码合同检查

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

  1. 使用代码合约“原生”前提条件:
    • 公共 API方法上使用Contract.Requires<TException>(例如,您的图书馆用户将要调用的方法),您希望针对这些方法投放特定的例外情况,例如ArgumentException
    • 使用Contract.Requires 非公开 API方法 公共 您不想抛出特定异常的API方法
    • 启用 运行时检查所有版本上的
    • 确保您 启用 选项,仅在您的程序集的公共表面区域上发出前置条件 -例如只有那些可供您的图书馆消费者调用的方法。
  2. 使用“遗留”合同检查:
    • 这是您的公共 API方法上的旧学校风格if (cond) { throw new Exception(...) }保护阻止
    • 使用手动继承来强制派生类型的合同。 (当使用选项1时,代码约定可以从基类执行合同的自动继承,帮助您避免违反Liskov替换原则。)
    • 确保在所有Contracts.EndContractBlock()块之后放置if (cond) { throw new Exception(...) }行,以便代码合同知道这些是您的合同。
    • 非公开 API方法上,您可以随意使用Contract.Requires作为合同。
    • 启用 仅在调试版本上运行时检查
  3. 关于上述内容需要注意的一点是:在调试版本中,合同检查始终启用。如果您团队中的其他开发人员将构建此库,则他们还需要安装代码合同。

    第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 版本上运行。