代码契约:为什么有些不变量不在类之外考虑?
考虑这个不可变类型:
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
不能为空(因为 Settings 具有相应的契约不变性),- 所以通过将
settings.Path
分配给_path
,_path
不能为 null
我在这里错过了什么吗?
Consider this immutable type:
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;
}
}
Two things to notice here:
- There is a contract invariant which ensures the
Path
property can never benull
- The constructor checks the
path
argument value to respect the previous contract invariant
At this point, a Setting
instance can never have a null
Path
property.
Now, look at this type:
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"
}
Basically, it has its own contract invariant (on _path
field) that can't be satisfied during static checking (cf. comment above). That sounds a bit weird to me, since it's easy to prove it:
settings
is immutablesettings.Path
can't be null (because Settings has the corresponding contract invariant)- so by assigning
settings.Path
to_path
,_path
can't be null
Did I miss something here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
检查代码契约论坛后,我发现这个类似的问题,其中一个答案如下开发商:
换句话说,您的选择是:
使
Settings.Path
属性显式而不是自动,并在支持字段上指定不变量。为了满足您的不变量,您需要向属性的 set 访问器添加一个前提条件:Contract.Requires(value != null)
。您可以选择使用
Contract.Ensures(Contract.Result() != null)
将后置条件添加到 get 访问器,但静态检查器不会抱怨任何一种情况。将
Contract.Assume(settings.Path != null)
添加到Program
类的构造函数。After checking the code contracts forum, I found this similar question with the following answer from one of the developers:
So in other words, your options are:
Make the
Settings.Path
property explicit instead of automatic, and specify the invariant on the backing field instead. In order to satisfy your invariant, you will need to add a precondition to the property's set accessor:Contract.Requires(value != null)
.You can optionally add a postcondition to the get accessor with
Contract.Ensures(Contract.Result<string>() != null)
, but the static checker will not complain either way.Add
Contract.Assume(settings.Path != null)
to the constructor of theProgram
class.不变量不适用于私有成员,您实际上无法知道为什么会这样,希望这会有所帮助。
Invariants don't work on private members, you cannot actually have the reason why it is this way, hope this helps.