11

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

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

return id.Value;

代码合同错误:需要未经证实:HasValue

4

3 回答 3

6

我已经深入了解了这种行为,这不是代码合同的错。

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

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

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

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

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

于 2011-07-27T16:05:07.307 回答
1

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

于 2011-07-27T16:01:43.423 回答
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

于 2011-07-27T16:06:58.240 回答