为什么 Code Contracts 建议我要求参数为空?

Why is Code Contracts suggesting that I require a parameter to be null?

查看下面的代码示例,Microsoft Code Contracts 警告:

CodeContracts: Missing precondition in an extremely visible method. Consider adding Contract.Requires(science == null); for parameter validation

我是不是漏掉了什么?为什么CC会建议我要求参数为null,这与这里应该做的完全相反?

我正在使用 VS2015、.NET 4.6。

using System;
using System.Diagnostics.Contracts;
public sealed class Weird
{

    public Weird(object science)
    {
        if (null == science)
        {
            throw new ArgumentNullException();
        }

        Contract.EndContractBlock();

        this.Science = science;
    }
    private object Science { get; }

    [ContractInvariantMethod]
    private void ObjectInvariant()
    {
        Contract.Invariant(null != this.Science);
    }
}

尽量不要使用反向比较。在 C# 中,无需编写:

if (null == science)

而不是

if (science == null)

你的代码会变得更清晰,我想错误的合约建议也会消失。

另外,如果你犯了一个错误,只在 if 块中写了一个赋值 (=),编译器会警告你。

为了使您的代码更加清晰,您可以尝试使用一些 AOP 工具,例如 PostSharp,并将您的合同指定为接口中的 属性 属性,您的 class 将实现该属性。因此合同逻辑不会与业务逻辑交织。

我发现当我用字段支持的 属性 替换自动 属性 时警告消失了。将以下代码与我在原始问题中发布的代码进行比较:

using System;
using System.Diagnostics.Contracts;
public sealed class Weird
{        
    public Weird(object science)
    {
        if (science == null)
        {
            throw new ArgumentNullException();
        }

        Contract.EndContractBlock();

        this.science = science;
    }

    private readonly object science;

    private object Science
    {
        get
        {
            return this.science;
        }
    }

    [ContractInvariantMethod]
    private void ObjectInvariant()
    {
        Contract.Invariant(null != this.Science);
    }
}

我不喜欢这个,因为我不一定要使用现场支持 属性 只是为了满足代码合同的目的。但是,哦,好吧,我想。

我仍然愿意接受允许我在使用汽车属性时满足我的合同的答案。

这不是比您的解决方法更好的答案,但我通过简单地更改 "work" 得到了它:

private object Science { get; }

至:

private object Science { get; set; }

与您的解决方法基本相同,但不提供您自己的支持字段。我猜 Code Contracts 不太理解新语法。

根据变通方法,CC 似乎不明白只读自动 属性 在构造函数中是可写的。提供的两种解决方法都删除了写入只读 属性 的操作。也许 CC 试图通过将执行发送到唯一可用的其他分支 ( null == science ).

来避免执行它认为有错误的语句 ( this.Science = science; )。

早期版本的 C# 不允许写入只读自动 属性。我猜代码合同系统没有收到备忘录!