.net 4.0 在对象不变量的代码中我能有多自由?

.net 4.0 在对象不变量的代码中我能有多自由?,.net-4.0,code-contracts,visual-studio-2010,invariants,.net 4.0,Code Contracts,Visual Studio 2010,Invariants,我试图演示代码契约中的不变量,我想我应该给出一个字符串排序列表的示例。它在内部维护一个数组,并留出空间用于添加内容等——基本上就像List。当它需要添加一个项目时,它会将其插入数组中,等等。我想我有三个不变量: 计数必须合理:非负,最多与缓冲区大小一样大 缓冲区未使用部分中的所有内容都应为空 缓冲区的已用部分中的每个项应至少与之前的项一样“大” 现在,我尝试通过以下方式实现: [ContractInvariantMethod] private void ObjectInvariant() {

我试图演示代码契约中的不变量,我想我应该给出一个字符串排序列表的示例。它在内部维护一个数组,并留出空间用于添加内容等——基本上就像
List
。当它需要添加一个项目时,它会将其插入数组中,等等。我想我有三个不变量:

  • 计数必须合理:非负,最多与缓冲区大小一样大
  • 缓冲区未使用部分中的所有内容都应为空
  • 缓冲区的已用部分中的每个项应至少与之前的项一样“大”
现在,我尝试通过以下方式实现:

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(count >= 0 && count <= buffer.Length);
    for (int i = count; i < buffer.Length; i++)
    {
        Contract.Invariant(buffer[i] == null);
    }
    for (int i = 1; i < count; i++)
    {
        Contract.Invariant(string.Compare(buffer[i], buffer[i - 1]) >= 0);
    }
}
这有点难看,尽管它确实有效。(请注意,这比我以前的尝试要好得多。)

我的期望不合理吗?我的不变量不合理吗

(也被问到。我会自己在这里添加任何相关的答案。)

从(初步)MSDN页面上看,它看起来像是一份合同。因为所有会员都可以帮助您处理这两份范围内的合同。不过,文档中并没有明确说明它的功能

//untested
Contract.Invariant(Contract.ForAll(count, buffer.Length, i => buffer[i] == null));
Contract.Invariant(Contract.ForAll(1, count, 
    i => string.Compare(buffer[i], buffer[i - 1]) >= 0));
(我将接受亨克的回答,但我认为值得补充这一点。)

现在问题已经在上得到了回答,结果是第一种形式预计不会起作用。不变量真的,真的需要一系列调用
Contract.Invariant
,仅此而已

这使得静态检查器更容易理解并执行不变量

只需将所有逻辑放入不同的成员(例如
IsValid
属性)中,然后调用:

Contract.Invariant(IsValid);

这无疑会搞乱静态检查器,但在某些情况下,它在某些情况下可能是一个有用的替代方案。

设计师不是有点重新发明轮子吗

这辆车怎么了

?

现在在C#中我们没有常数,但是为什么不能定义一个
不变量
函数呢

private bool Invariant()
{
  // All the logic, function returns true if object is valid i.e. function
  // simply will never return false, in the absence of a bug
}
// Good old invariant in C#, no special attributes, just a function
然后就用这个函数的代码契约

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(Invariant() == true);
}

也许我写的是胡说八道,但即使在这种情况下,当每个人都告诉我错了的时候,它也有一定的教育价值。

显然,你不能像循环一样自由/奇怪的是,第一个循环没有问题。。。但第二个不是。当然,这可能是ccrewrite中的一个bug。(我怀疑它在调用Contract之前捕获了所有代码。不变量…)Jon,ForAll是[a,b],所以它应该是ForAll(1,count,…),而不是count-1哦,是的。显然今晚没有直接思考。我可以将ForAll用于第一个(如果不变量中允许的话)但第二个一次需要两个元素,这有点棘手。有两个版本,一个是基于整数范围并使用谓词的。我添加了一个示例说明它是如何工作的。非常感谢这个Henk-它看起来肯定比以前更好。我使用了buffer.Skip()第一个版本是正常的,但第二个版本显然是相同的:)事实上,现在我看了一下,我觉得我更喜欢你的版本,因为它更接近初始代码。再次编辑。我现在还不接受答案,因为我仍然想知道是否预期我的初始代码不会工作。我在一个ol中发现der在去年4月发布了这个Contract.ForAll还没有得到支持(静态):这和我的建议差不多。我将把它作为一个“有效的”使用.Net代码协定时的模式。您可以这样做,但是静态检查器几乎没有任何信息可用于确保不变量保持完整。如果可能,最好使用一组对协定.invariant的调用。@Jon我明白了。传统上,不变量不是静态检查的,只是在协定之前和之后调用我知道代码契约试图引入静态分析值。不过,我还需要了解它在实践中是如何工作的。
private bool Invariant()
{
  // All the logic, function returns true if object is valid i.e. function
  // simply will never return false, in the absence of a bug
}
// Good old invariant in C#, no special attributes, just a function
[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(Invariant() == true);
}