按契约设计:你能有一个协议接口吗?

发布于 2024-07-30 07:09:00 字数 2192 浏览 6 评论 0原文

我对契约设计的概念还很陌生,但到目前为止,我很喜欢它让发现潜在错误变得多么容易。

然而,我一直在使用 Microsoft.Contracts 库(这非常棒),但我遇到了障碍。

以我想要做的这个简化示例为例:

public enum State { NotReady, Ready }

[ContractClass(typeof(IPluginContract))]
public interface IPlugin
{
    State State { get; }
    void Reset();
    void Prepare();
    void Run();
}

[ContractClassFor(typeof(IPlugin))]
public class IPluginContract : IPlugin
{
    State IPlugin.State { get { throw new NotImplementedException(); } }

    void IPlugin.Reset()
    {
        Contract.Ensures(((IPlugin)this).State == State.NotReady);
    }

    void IPlugin.Prepare()
    {
        Contract.Ensures(((IPlugin)this).State == State.Ready);
    }

    void IPlugin.Run()
    {
        Contract.Requires(((IPlugin)this).State == State.Ready);
    }
}

class MyAwesomePlugin : IPlugin
{
    private State state = State.NotReady;

    private int? number = null;

    State IPlugin.State
    {
        get { return this.state; }
    }

    void IPlugin.Reset()
    {
        this.number = null;
        this.state = State.NotReady;
    }

    void IPlugin.Prepare()
    {
        this.number = 10;
        this.state = State.Ready;
    }

    void IPlugin.Run()
    {
        Console.WriteLine("Number * 2 = " + (this.number * 2));
    }
}

总而言之,我声明了一个供插件遵循的接口,并要求它们声明其状态,并限制在任何状态下可以调用的内容。

这适用于调用站点,用于静态和运行时验证。 但对于 ResetPrepare 函数,我不断收到的警告是“合同:确保未经验证”。

我尝试过用 Invariant 进行欺骗,但这并不能帮助证明 Ensures 约束。

关于如何通过界面证明的任何帮助都会有所帮助。

编辑1:

当我将其添加到 MyAwesomePlugin 类时:

    [ContractInvariantMethod]
    protected void ObjectInvariant()
    {
        Contract.Invariant(((IPlugin)this).State == this.state);
    }

试图暗示作为 IPlugin 的状态与我的私有状态相同,我收到相同的警告,并且警告“private int? number = null”行未能证明不变式。

鉴于这是静态构造函数中的第一个可执行行,我可以理解为什么它会这么说,但为什么这不能证明 Ensures 呢?

EDIT2

当我用 [ContractPublicPropertyName("State")] 标记 State 时,我收到一条错误消息,指出“没有名为 'State” 的公共字段/属性' 可以找到类型为 'MyNamespace.State' 的内容”

似乎这应该让我更接近,但我还没有完全做到这一点。

I'm pretty new to the concept of Design by Contract, but so far, I'm loving how easy it makes it to find potential bugs.

However, I've been working with the Microsoft.Contracts library (which is pretty great,) and I have run into a road block.

Take this simplified example of what I'm trying to do:

public enum State { NotReady, Ready }

[ContractClass(typeof(IPluginContract))]
public interface IPlugin
{
    State State { get; }
    void Reset();
    void Prepare();
    void Run();
}

[ContractClassFor(typeof(IPlugin))]
public class IPluginContract : IPlugin
{
    State IPlugin.State { get { throw new NotImplementedException(); } }

    void IPlugin.Reset()
    {
        Contract.Ensures(((IPlugin)this).State == State.NotReady);
    }

    void IPlugin.Prepare()
    {
        Contract.Ensures(((IPlugin)this).State == State.Ready);
    }

    void IPlugin.Run()
    {
        Contract.Requires(((IPlugin)this).State == State.Ready);
    }
}

class MyAwesomePlugin : IPlugin
{
    private State state = State.NotReady;

    private int? number = null;

    State IPlugin.State
    {
        get { return this.state; }
    }

    void IPlugin.Reset()
    {
        this.number = null;
        this.state = State.NotReady;
    }

    void IPlugin.Prepare()
    {
        this.number = 10;
        this.state = State.Ready;
    }

    void IPlugin.Run()
    {
        Console.WriteLine("Number * 2 = " + (this.number * 2));
    }
}

To sum it up, I am declaring an interface for plugins to follow, and requiring them to declare their state, and limiting what can be called in any state.

This works at the call site, for both static and runtime validation. But the warning I keep getting is "contracts: ensures unproven" for both the Reset and Prepare functions.

I have tried finagling with Invariants, but that doesn't seen to aid in proving the Ensures constraint.

Any help as to how to prove through the interface would be helpful.

EDIT1:

When I add this to the MyAwesomePlugin class:

    [ContractInvariantMethod]
    protected void ObjectInvariant()
    {
        Contract.Invariant(((IPlugin)this).State == this.state);
    }

Attempting to imply that the state as an IPlugin is the same as my private state, I get the same warnings, AND a warning that the "private int? number = null" line fails to prove the invariant.

Given that that is the first executable line in the static constructor I can see why it may say so, but why doesn't that prove the Ensures?

EDIT2

When I mark State with [ContractPublicPropertyName("State")] I get an error saying that "no public field/property named 'State' with type 'MyNamespace.State' can be found"

Seems like this should put me closer, but I'm not quite there.

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

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

发布评论

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

评论(1

慵挽 2024-08-06 07:09:00

通过这个代码片段,我有效地抑制了警告:

    void IPlugin.Reset()
    {
        this.number = null;
        this.state = State.NotReady;
        Contract.Assume(((IPlugin)this).State == this.state);
    }

这实际上回答了我的第一个问题,但提出了一个新问题:为什么不变量没有帮助证明这一点?

我将发布一个新问题。

With this code snippet, I effectively suppressed the warning:

    void IPlugin.Reset()
    {
        this.number = null;
        this.state = State.NotReady;
        Contract.Assume(((IPlugin)this).State == this.state);
    }

This actually answers my first question, but asks a new one: Why didn't the invariant help prove this?

I will be posting a new question.

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