我有以下情况:
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}因此无法添加需求
这里最好的事情是什么?我看到的选项包括
Contract.Assume
请注意,该字段为readonly
,因此在构造函数中设置值后,无法更改。因此,来自代码合同的警告似乎有点无关紧要。
答案 0 :(得分:19)
如果客户端确保他们满足前提条件并且具有静态类型为
o
的变量T
,那么客户端在调用o.M
时不应该违反前提条件。即使运行时值o
具有类型U
,也必须如此。因此,方法U.M
无法添加强于T.M
前提条件的前提条件。虽然我们可以允许较弱的前提条件,但我们发现这样做的复杂性超过了益处。我们还没有看到任何令人信服的例子,削弱前提条件是有用的。所以我们不允许在子类型中添加任何先决条件。
因此,方法前置条件必须在继承/实现链的根方法上声明,即第一个虚拟或抽象方法声明,或接口方法本身。
在您的情况下,最好的做法是设置一个不变的声明_somethingElse
字段永远不为空:
[ContractInvariantMethod]
private void ObjectInvariant() {
Contract.Invariant(_somethingElse != null);
}
这当然总是正确的,因为字段标记为readonly
并在构造函数中初始化。静态检查器无法自行推断,因此您必须通过该不变量明确告知它。
您可以选择将后置条件Contract.Ensures(_somethingElse != null);
添加到构造函数中,但静态检查器不需要它。