代码合同是否未能发现Nullable <t> .HasValue和null之间的明显关系?</t>

时间:2011-07-27 15:15:21

标签: c# code-contracts static-code-analysis

我正在尝试将代码契约应用于我的代码,我遇到了一个令人困惑的问题。 这段代码无法满足合同,但除非我真的很厚,否则我希望它能够轻松分析id在返回时必须有一个值

if (id == null)
    throw new InvalidOperationException(string.Format("{0} '{1}' does not yet have an identity", typeof(T).Name, entity));

return id.Value;

Code Contracts error: requires unproven: HasValue

3 个答案:

答案 0 :(得分:6)

我已经了解了这种行为,并且这不是Code Contract的错。

我在ILSpy中打开了生成的程序集,这是生成的代码:

public Guid Id
{
    get
    {
        Guid? guid = this.id;
        if (!guid.HasValue)
        {
            throw new InvalidOperationException();
        }
        guid = this.id;
        return guid.Value;
    }
}

正在将实例变量id复制到局部变量,并且在条件块之后将此局部变量重置回其原始值。现在很明显为什么Code Contracts显示合同违规错误,但仍然让我感到困惑,为什么代码被重写为这种形式。我做了一些实验,并将Code Contracts完全从项目中删除,很明显这是标准的C#编译器行为,但为什么呢?

这个秘密似乎是由于我在原始问题中不小心遗漏的一个小细节。 id实例变量声明为readonly,这似乎是导致编译器添加临时guid变量的原因。

我必须承认,我仍然感到困惑,为什么编译器认为需要这样做以确保id的不变性保证,但我会继续挖掘......

答案 1 :(得分:1)

您可以尝试将字段复制到本地值,并根据该本地值编写语句。证明者可能对字段保守,因为调用可能会改变字段值。

答案 2 :(得分:0)

它没有看到你的if throw支票作为其合约的一部分。试试这个:

if (id == null)    
  throw new InvalidOperationException(string.Format("{0} '{1}' does not yet have an identity", typeof(T).Name, entity));

Contract.EndContractBlock();

http://msdn.microsoft.com/en-us/library/system.diagnostics.contracts.contract.endcontractblock.aspx