代码契约[Type]实现接口方法{Interface.Method},因此无法添加要求

发布于 2024-09-13 04:30:29 字数 861 浏览 4 评论 0原文

我有以下场景:

public interface ISomething
{
    void DoStuff();
    //...
}

public class Something : ISomething
{
    private readonly ISomethingElse _somethingElse;
    //...

    public Something (ISomethingElse somethingElse)
    {
         Contract.Requires(somethingElse != null);
        _somethingElse = somethingElse;
    }

    public void DoStuff()
    {
        // *1* Please look at explanation / question below
        _somethingElse.DoThings();
    }
 }

在第 1 行并打开静态检查器时,我会收到一条警告,指出 _somethingElse 可能为空,如果我添加合同会给我错误

[Type]实现接口方法{Interface.Method},因此无法添加要求

这里最好做什么?我看到的选项包括

  1. 一个保护条款,尽管它似乎是 有点极端
  2. Contract.Assume
  3. 我没有想到的隐藏的第三个选项

请注意,该字段是只读,因此在构造函数中设置值后,不可能改变。因此,代码合约的警告似乎有点无关紧要。

I have the following scenario:

public interface ISomething
{
    void DoStuff();
    //...
}

public class Something : ISomething
{
    private readonly ISomethingElse _somethingElse;
    //...

    public Something (ISomethingElse somethingElse)
    {
         Contract.Requires(somethingElse != null);
        _somethingElse = somethingElse;
    }

    public void DoStuff()
    {
        // *1* Please look at explanation / question below
        _somethingElse.DoThings();
    }
 }

At line 1 and with the static checker on, I'll get a warning saying that _somethingElse is possibly null, and if I add a contract it will give me the error

[Type]implements interface method {Interface.Method} thus cannot add requires

What's the best thing to do here? Options I see include

  1. a guard clause, though it seems a
    bit extreme
  2. a Contract.Assume
  3. a hidden third option that I haven't thought of

Please note the field is readonly so after setting the value in the constructor it is not possible to change. Thus, the warning from code contracts seems a bit irrelevant.

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

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

发布评论

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

评论(1

征﹌骨岁月お 2024-09-20 04:30:29

说明

用户手册的第 3 节:合同继承 声明所有前提条件必须在继承/实现链的根方法中定义:

如果客户端确保他们已经满足前提条件并且有一个静态类型为 T 的变量 o,那么当客户端致电oM。即使运行时值 o 的类型为 U,也必须如此。因此,UM 方法无法添加比 TM 的前提条件更强的前提条件。

虽然我们可以允许较弱的前提条件,但我们发现这样做的复杂性超过了好处。我们只是还没有看到任何令人信服的例子来证明弱化前提条件是有用的。因此我们根本不允许在子类型中添加任何先决条件。

因此,方法前置条件必须在继承/实现链的根方法上声明,即第一个虚拟或抽象方法声明,或接口方法本身。

解决方案

在您的情况下,最好的做法是设置一个不变量,声明 _somethingElse 字段永远不为空:

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

这当然总是正确的,因为该字段被标记为 readonly 并在构造函数中初始化。不过,静态检查器无法自行推断这一点,因此您必须通过该不变量显式地告诉它。

您可以选择向构造函数添加后置条件 Contract.Ensures(_somethingElse != null);,但静态检查器不需要它。

Explanation

Section 3: Contract Inheritance of the user manual states that all preconditions must be defined in the root method of an inheritance/implementation chain:

If a client makes sure that they have satisfied the precondition and has a variable o whose static type is T, then the client should not get a precondition violation when they call o.M. This needs to be true even if the runtime value o has type U. Therefore, the method U.M cannot add a precondition that is stronger than the precondition of T.M.

While we could allow a weaker precondition, we have found that the complications of doing so outweigh the benefits. We just haven't seen any compelling examples where weakening the precondition is useful. So we do not allow adding any preconditions at all in a subtype.

As a consequence, method preconditions must be declared on the root method of an inheritance/implementation chain, i.e., the first virtual or abstract method declaration, or the interface method itself.

Solution

In your situation, the best course of action is to set up an invariant stating that the _somethingElse field is never null:

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

This is of course always true, as the field is marked readonly and initialised in the constructor. The static checker isn't able to infer this on its own though, so you must explicitly tell it through that invariant.

You can optionally add a postcondition Contract.Ensures(_somethingElse != null); to your constructor, but the static checker doesn't require it.

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