考虑这种不可变类型:
public class Settings
{
public string Path { get; private set; }
[ContractInvariantMethod]
private void ObjectInvariants()
{
Contract.Invariant(Path != null);
}
public Settings(string path)
{
Contract.Requires(path != null);
Path = path;
}
}
这里有两点需要注意:
Path
属性永远不会null
path
参数值以尊重先前的合约不变量此时,Setting
实例永远不会拥有null
Path
属性。
现在,看看这种类型:
public class Program
{
private readonly string _path;
[ContractInvariantMethod]
private void ObjectInvariants()
{
Contract.Invariant(_path != null);
}
public Program(Settings settings)
{
Contract.Requires(settings != null);
_path = settings.Path;
} // <------ "CodeContracts: invariant unproven: _path != null"
}
基本上,它有自己的契约不变量(在_path
字段上),在静态检查期间无法满足(参见上面的评论)。这对我来说听起来有点奇怪,因为它很容易证明:
settings
是不可变的settings.Path
不能为null(因为“设置”具有相应的合约不变量)settings.Path
分配给_path
,_path
不能为空我在这里错过了什么吗?
答案 0 :(得分:10)
检查code contracts forum后,我发现了this similar question,其中一位开发人员给出了以下答案:
我认为您遇到的行为是由正在进行的某种方法间推断引起的。静态检查器首先分析构造函数,然后分析属性,然后分析方法。在分析Sample的构造函数时,它不知道msgContainer.Something!= null,因此它会发出警告。解决它的方法是在构造函数中添加一个假设msgContainer.Something!= null,或者更好地将postcondition!= null添加到Something。
换句话说,您的选择是:
使Settings.Path
属性显式而不是自动,并在支持字段中指定不变量。为了满足您的不变量,您需要为属性的set访问器添加前置条件:Contract.Requires(value != null)
。
您可以选择使用Contract.Ensures(Contract.Result<string>() != null)
向get访问者添加后置条件,但静态检查器不会以任何方式投诉。
将Contract.Assume(settings.Path != null)
添加到Program
类的构造函数中。
答案 1 :(得分:0)
不变量不在私人会员身上工作,你实际上无法理解为什么会这样,希望这会有所帮助。