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

时间:2010-08-05 12:19:37

标签: c# code-contracts

我有以下情况:

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可能为空,如果我添加一个合同,它会给我错误< / p>

  

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

这里最好的事情是什么?我看到的选项包括

  1. 一个保护条款,虽然它似乎是一个 有点极端
  2. a Contract.Assume
  3. 我没有想到的隐藏的第三个选项
  4. 请注意,该字段为readonly,因此在构造函数中设置值后,无法更改。因此,来自代码合同的警告似乎有点无关紧要。

1 个答案:

答案 0 :(得分:19)

说明

user manual的第3部分:合同继承声明必须在继承/实现链的根方法中定义所有前提条件:

  

如果客户端确保他们满足前提条件并且具有静态类型为o的变量T,那么客户端在调用o.M时不应该违反前提条件。即使运行时值o具有类型U,也必须如此。因此,方法U.M无法添加强于T.M前提条件的前提条件。

     

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

     

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

解决方案

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

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

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

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