代码契约是否未能发现 Nullable.HasValue 和 null 之间的明显关系?

发布于 2024-11-26 18:05:48 字数 362 浏览 3 评论 0原文

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

if (id == null)
    throw new InvalidOperationException(string.Format("{0} '{1}' 尚无标识", typeof(T).Name,entity));

返回 id.Value;

代码合约错误:需要未经验证:HasValue

I am experimenting with applying Code Contracts to my code and I've hit a perplexing problem.
This code is failing to meet the contract but unless I'm being really thick I would expect it to be able to easily analyse that id must have a value at the point of return

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

唯憾梦倾城 2024-12-03 18:05:48

我已经查清了这种行为的真相,这不是 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 的不变性保证,但我会继续挖掘......

I've got to the bottom of this behaviour and it is not Code Contract's fault.

I opened the generated assembly in ILSpy and this is the code that is produced:

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

The instance variable id is being copied to a local variable and this local variable is being reset back to its original value after the condition block. Now it became obvious why Code Contracts is showing a contract violation error but it still left me confused why the code was being rewritten in this form. I did a little more experimentation and took Code Contracts out of the project altogether and it became apparent that this is standard C# compiler behaviour, but why?

The secret appears to be due to a minor detail that I accidentally omitted from my original question. The id instance variable is declared as readonly and this seems to be responsible for causing the compiler to add the temporary guid variable.

I must admit I'm still confused why the compiler feels it needs to do this to ensure the guarantee of immutability for id but I'll keep digging...

旧竹 2024-12-03 18:05:48

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

You might try copying the field to a local value and writing the statements in terms of that local value. The prover may be conservative about fields, since it's possible that a call could mutate the field value.

多孤肩上扛 2024-12-03 18:05:48

它没有看到你的 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

Its not seeing your if throw check as part of its contracts. Try this instead:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文