我正在尝试将代码合约应用到我的代码中,但我遇到了一个令人困惑的问题。
这段代码未能满足合约,但除非我真的很愚蠢,否则我希望它能够轻松地分析出在返回点上id
必须有一个值。
if (id == null)
throw new InvalidOperationException(string.Format("{0} '{1}' does not yet have an identity", typeof(T).Name, entity));
return id.Value;
我正在尝试将代码合约应用到我的代码中,但我遇到了一个令人困惑的问题。
这段代码未能满足合约,但除非我真的很愚蠢,否则我希望它能够轻松地分析出在返回点上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 Contract的问题。
我在ILSpy中打开了生成的程序集,这就是生成的代码:
public Guid Id
{
get
{
Guid? guid = this.id;
if (!guid.HasValue)
{
throw new InvalidOperationException();
}
guid = this.id;
return guid.Value;
}
}
id
被复制到一个本地变量中,而这个本地变量在条件块后被重置回其原始值。现在显然为什么代码合同显示合同违规错误,但它仍然让我困惑的是为什么代码被以这种形式重写。我进行了更多的实验,并完全将代码合同从项目中删除,很明显这是标准的C#编译器行为,但为什么呢?id
实例变量声明为readonly
,这似乎是导致编译器添加临时guid
变量的原因。id
的不可变性保证,但我会继续深入研究...readonly
字段不是变量。与属性类似,它们被视为值,对于值类型来说,这意味着对它们的所有操作必须在副本上执行。因此,就像访问值类型的属性一样,每次访问值类型的readonly
字段时都会产生一个副本。我知道这一点正是我根据反编译代码推测出你的问题的原因。 - Sven你可以尝试将字段复制到本地变量中,并使用该本地变量编写语句。证明器可能会对字段保守,因为调用可能会改变字段值。
它没有将你的 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
!id.HasValue
吗? - Daniel A. White