2

一旦您在项目属性中禁用运行时合同检查,就会为合同类引发 FxCop 违规(假设您通过接口实现合同,然后在抽象类中定义合同)。

重新启用运行时合同检查,所有违规行为都消失了。

这是什么原因?

违规行为如:

CA1811 ObjectInvariant 似乎没有上游调用者

CA1033 使 MyClassContract 密封

这没有意义,因为合同类必须是抽象的。

4

1 回答 1

6

好吧,我想我明白你的意思了。你有像凯文这样的类,用一个AccountContracts名为而不是MyClassContract私有方法命名:ObjectInvariantsInvariants

[ContractClassFor(typeof(IAccount))]
public abstract class MyClassContract : IAccount
{
    public abstract double Balance { get; }

    void IAccount.Deposit(double amount)
    {
        Contract.Requires(amount >= 0.0d);

        //throw new NotImplementedException();
    }

    bool IAccount.Withdraw(double amount)
    {
        Contract.Requires(amount >= 0.0d);
        Contract.Requires(amount <= Balance);

        throw new NotImplementedException();
    }

    [ContractInvariantMethod]
    private void ObjectInvariants()
    {
        Contract.Invariant(Balance >= 0.0d);
    }
}

FxCopy 和代码分析进行编译后分析。它分析二进制文件,即构建生成的中间语言 (IL)。Code Contracts 有点像进行后编译编织,因为它将代码生成到二进制文件中,该二进制文件不仅派生自您的抽象类MyClassContract,而且ObjectInvariants至少调用一次该方法。当您“关闭”代码合同时,它不再生成此代码,因此 FxCop 和代码分析看不到任何派生自MyClassContract或任何使用ObjectInvariants方法的内容,因此会警告您。在 的情况下MyClassContract,由于没有任何东西从它派生,它可以被密封(这有助于编译器在某些情况下略微优化)以及使类在将来更易于维护(没有什么可以从中派生,因此您可以更自由地更改它-至少这是普遍共识)。

当然,如果您希望代码在没有警告的情况下保持原样,您可以在抑制文件中抑制这些警告。您还可以包含一个编译器常量并包围代码以避免在不使用代码协定时编译,并在启用代码协定时将该常量包含在构建设置中。例如:

#if CODE_CONTRACTS
//...
#endif

创建一个新的构建配置通常是最简单的事情,因为您可以拥有一个特定的构建配置,它既可以启用代码契约,又可以CODE_CONTRACTS在项目的构建属性中声明。

于 2012-09-10T21:51:23.780 回答