当无法证明属性时,如何告诉静态检查器属性永远不会改变?

发布于 2024-09-28 19:06:48 字数 1613 浏览 1 评论 0原文

我的类有一个在构造函数中初始化的属性,并且永远不应该更改。我的代码库周围的方法都接受该类作为参数,并依赖于满足特定条件的该属性。

关键是属性永远不变确实无法证明。我个人可以“发誓”它永远不会改变(并且我也对其进行了单元测试),但它无法被正式证明(或者至少我认为如此)。

考虑以下简化示例:

    public class ConstantPoperty
    {
        public class SomeClass
        {
            public int SomeProp { 
                get { return GetSomePropThroughUnprovableMechanism(); }
            }

            public SomeClass( int i )
            {
                SetSomePropThroughUnprovableMechanism( i );
            }
        }

        public void Method( SomeClass c )
        {
            Contract.Requires( c != null );
            Contract.Requires( c.SomeProp == 5 );
        }

        public void FalsePositive()
        {
            SomeClass c = new SomeClass( 5 );
            if ( c.SomeProp != 5 ) return;
            Method( c );
            Method( c ); // unproven requires: c.SomeProp == 5
        }
    }

请注意,对 Method() 的第一次调用从检查器中获得了 OK,因为我在它之前检查了条件是否满足。
然而,第二次调用会收到一个未经证实的警告。我的猜测是,检查器假设第一次调用 Method(c) 可能会更改 c.SomeProp ,以便它将不再满足条件。

由此,我可以推断出两种可能的解决方法,但我认为这两种方法都不可接受:

  1. Add Contract.Ensures( c.SomeProp == Contract.OldValue( c.SomeProp ) ) to 方法,以及接受 SomeClass 类型参数的所有其他方法。
    人们很容易看出这是多么荒谬。

  2. 在第二次调用 Method(c) 之前添加对 c.SomeProp == 5 的冗余检查。
    虽然这不像第一个选项那么荒谬,但它也是不可接受的,因为除了使代码变得混乱之外,它还会带来性能损失(这样的检查不会被优化掉)。

理想的解决方案是以某种方式说服检查器 SomeProp 在构造后永远不会改变,但我找不到任何方法来做到这一点。

或者也许我在这里遗漏了一些明显的东西?

My class has a property that is initialized in the constructor and is never supposed to change. Methods all around my codebase accept that class as a parameter and rely on that property satisfying a certain condition.

The key point is that it is really unprovable that the property never changes. I can personally "swear" that it never changes (and I have unit tests for it, too), but it cannot be proved formally (or at least I think so).

Consider the following reduced example:

    public class ConstantPoperty
    {
        public class SomeClass
        {
            public int SomeProp { 
                get { return GetSomePropThroughUnprovableMechanism(); }
            }

            public SomeClass( int i )
            {
                SetSomePropThroughUnprovableMechanism( i );
            }
        }

        public void Method( SomeClass c )
        {
            Contract.Requires( c != null );
            Contract.Requires( c.SomeProp == 5 );
        }

        public void FalsePositive()
        {
            SomeClass c = new SomeClass( 5 );
            if ( c.SomeProp != 5 ) return;
            Method( c );
            Method( c ); // unproven requires: c.SomeProp == 5
        }
    }

Note that the first call to Method() get an OK from the checker, since I've checked right before it that the condition is satisfied.
The second call, however, gets an unproven warning. My guess is, the checker assumes that the first call to Method(c) might change c.SomeProp so that it will no longer satisfy the condition.

From this, I can deduce two possible workarounds, neither of which I consider acceptable:

  1. Add Contract.Ensures( c.SomeProp == Contract.OldValue( c.SomeProp ) ) to Method, as well as to every other method that accepts arguments of type SomeClass.
    One can easily see how this is absolutely ridiculous.

  2. Add a redundant check for c.SomeProp == 5 before the second call to Method(c).
    While this is less ridiculous than the first option, it is also unacceptable, because in addition to cluttering the code, it will also have a performance penalty (such a check will not be optimized away).

The ideal solution would be to somehow convince the checker that SomeProp is never supposed to change after construction, but I couldn't find any way to do this.

Or maybe I am missing something obvious here?

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

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

发布评论

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

评论(1

强辩 2024-10-05 19:06:48

像这样重写它:

public class SomeClass
{
    private readonly int _someProp;

    public int SomeProp { get { return _someProp; } }

    public SomeClass(int i)
    {
        _someProp = i;
    }
}

Rewrite it like this:

public class SomeClass
{
    private readonly int _someProp;

    public int SomeProp { get { return _someProp; } }

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