代码契约:为什么有些不变量不在类之外考虑?

发布于 2024-09-12 04:17:12 字数 1317 浏览 3 评论 0原文

考虑这个不可变类型:

public class Settings
{
    public string Path { get; private set; }

    [ContractInvariantMethod]
    private void ObjectInvariants()
    {
        Contract.Invariant(Path != null);
    }

    public Settings(string path)
    {
        Contract.Requires(path != null);
        Path = path;
    }
}

这里需要注意两件事:

  • 有一个契约不变量,它确保 Path 属性永远不会是 null
  • 构造函数检查 path > 参数值尊重先前的契约不变式

此时,Setting 实例永远不能具有 null Path 属性。

现在,看看这个类型:

public class Program
{
    private readonly string _path;

    [ContractInvariantMethod]
    private void ObjectInvariants()
    {
        Contract.Invariant(_path != null);
    }

    public Program(Settings settings)
    {
        Contract.Requires(settings != null);
        _path = settings.Path;
    } // <------ "CodeContracts: invariant unproven: _path != null"
}

基本上,它有自己的契约不变量(在 _path 字段上),在静态检查期间无法满足(参见上面的评论)。这对我来说听起来有点奇怪,因为很容易证明这一点:

  • settings 是不可变的
  • settings.Path 不能为空(因为 Settings 具有相应的契约不变性),
  • 所以通过将 settings.Path 分配给 _path_path 不能为 null

我在这里错过了什么吗?

Consider this immutable type:

public class Settings
{
    public string Path { get; private set; }

    [ContractInvariantMethod]
    private void ObjectInvariants()
    {
        Contract.Invariant(Path != null);
    }

    public Settings(string path)
    {
        Contract.Requires(path != null);
        Path = path;
    }
}

Two things to notice here:

  • There is a contract invariant which ensures the Path property can never be null
  • The constructor checks the path argument value to respect the previous contract invariant

At this point, a Setting instance can never have a null Path property.

Now, look at this type:

public class Program
{
    private readonly string _path;

    [ContractInvariantMethod]
    private void ObjectInvariants()
    {
        Contract.Invariant(_path != null);
    }

    public Program(Settings settings)
    {
        Contract.Requires(settings != null);
        _path = settings.Path;
    } // <------ "CodeContracts: invariant unproven: _path != null"
}

Basically, it has its own contract invariant (on _path field) that can't be satisfied during static checking (cf. comment above). That sounds a bit weird to me, since it's easy to prove it:

  • settings is immutable
  • settings.Path can't be null (because Settings has the corresponding contract invariant)
  • so by assigning settings.Path to _path, _path can't be null

Did I miss something here?

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

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

发布评论

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

评论(2

被你宠の有点坏 2024-09-19 04:17:12

检查代码契约论坛后,我发现这个类似的问题,其中一个答案如下开发商:

我认为您遇到的行为是由正在进行的某些方法间推理引起的。静态检查器首先分析构造函数,然后分析属性,最后分析方法。在分析 Sample 的构造函数时,它不知道 msgContainer.Something != null,因此会发出警告。解决这个问题的一种方法是在构造函数中添加假设 msgContainer.Something != null ,或者更好地将后置条件 != null 添加到 Something 中。

换句话说,您的选择是:

  1. 使 Settings.Path 属性显式而不是自动,并在支持字段上指定不变量。为了满足您的不变量,您需要向属性的 set 访问器添加一个前提条件:Contract.Requires(value != null)

    您可以选择使用 Contract.Ensures(Contract.Result() != null) 将后置条件添加到 get 访问器,但静态检查器不会抱怨任何一种情况。

  2. Contract.Assume(settings.Path != null) 添加到 Program 类的构造函数。

After checking the code contracts forum, I found this similar question with the following answer from one of the developers:

I think the behavior you are experiencing is caused by some inter-method inference that is going on. The static checker first analyzes the constructors, then the properties and then the methods. When analyzing the constructor of Sample, it does not know that msgContainer.Something != null so it issues the warning. A way to solve it, is either by adding an assumption msgContainer.Something != null in the constuctor, or better to add the postcondition != null to Something.

So in other words, your options are:

  1. Make the Settings.Path property explicit instead of automatic, and specify the invariant on the backing field instead. In order to satisfy your invariant, you will need to add a precondition to the property's set accessor: Contract.Requires(value != null).

    You can optionally add a postcondition to the get accessor with Contract.Ensures(Contract.Result<string>() != null), but the static checker will not complain either way.

  2. Add Contract.Assume(settings.Path != null) to the constructor of the Program class.

朕就是辣么酷 2024-09-19 04:17:12

不变量不适用于私有成员,您实际上无法知道为什么会这样,希望这会有所帮助。

Invariants don't work on private members, you cannot actually have the reason why it is this way, hope this helps.

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