为什么代码契约建议我需要一个参数为空?

本文关键字:一个 参数 契约 代码 为什么 | 更新日期: 2023-09-27 18:15:14

看下面的代码示例,微软代码契约警告:

CodeContracts:在极度可见的方法中缺少前提条件。考虑添加Contract。要求(科学== null);为参数验证

我错过了什么吗?为什么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);
    }
}

为什么代码契约建议我需要一个参数为空?

这不是一个比你的解决方案更好的答案,但我让它"工作"通过简单地改变:

private object Science { get; }

:

private object Science { get; set; }

基本上与你的变通方法相同,但没有提供你自己的支持字段。我猜Code Contracts不太理解新语法

尽量不要使用反向比较。在c#中没有必要写:

if (null == science)

代替

if (science == null)
你的代码将变得更清晰,我认为错误的合同建议将会消失。

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

为了使你的代码更清晰,你可以尝试使用一些AOP的东西,比如PostSharp,并将你的契约指定为接口中的属性属性,你的类将实现这些属性。因此,合同逻辑将不会与业务逻辑交叉。

根据变通方法,CC似乎不理解只读auto属性在构造函数中是可写的。提供的两种解决方法都消除了向只读属性写入的操作。也许CC试图通过将执行发送到唯一可用的其他分支(null == science)来避免执行它认为错误的语句(this.Science = science;)。

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

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

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);
    }
}

我不喜欢这样,因为我不需要仅仅为了满足代码契约而使用字段支持的属性。但是,哦,好吧,我想。

我仍然开放的答案,让我满足我的合同,而使用自动属性