我在对象不变的代码中有多自由?

时间:2009-07-30 20:34:39

标签: .net-4.0 code-contracts visual-studio-2010-beta-1 invariants

我正在尝试在代码契约中演示不变量,我想我会给出一个排序的字符串列表示例。它在内部维护一个数组,有额外的空间用于添加等 - 基本上就像List<T>一样。当它需要添加一个项目时,它会将它插入到数组中,等等。我想我有三个不变量:

  • 计数必须合理:非负数,最多与缓冲区大小一样大
  • 缓冲区未使用部分中的所有内容都应为null
  • 缓冲区的已使用部分中的每个项目应至少与其前面的项目一样“大”

现在,我试图以这种方式实现它:

[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);
    }
}

不幸的是,ccrewrite搞乱了循环。

用户文档说该方法应该是对Contract.Invariant的一系列调用。我是否真的必须像这样重写代码?

Contract.Invariant(count >= 0 && count <= buffer.Length);
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));

这有点难看,虽然它确实有效。 (这比我以前的尝试要好得多,请注意。)

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

(也以question in the Code Contracts forum的形式提问。我将在此自行添加相关答案。)

3 个答案:

答案 0 :(得分:8)

从(初步)MSDN页面看,Contract.ForAll成员可以帮助您完成2个范围合同。虽然文档的功能不是很明确。

//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));

答案 1 :(得分:3)

(我将接受Henk的回答,但我认为值得加上这个。)

问题现在已在MSDN forum上得到解答,结果是第一种形式不是预期可行。不变量确实需要对Contract.Invariant进行一系列调用,而这就是全部。

这使静态检查器更容易理解不变量并强制执行它。

通过简单地将所有逻辑放入不同的成员,例如,可以避免这种限制。 IsValid属性,然后调用:

Contract.Invariant(IsValid);

毫无疑问,这会破坏静态检查程序,但在某些情况下,在某些情况下它可能是一个有用的替代方案。

答案 2 :(得分:1)

设计师不是要重新发明轮子吗?

good old

出了什么问题
bool Invariant() const; // in C++, mimicking Eiffel

现在在C#中我们没有const,但为什么你不能只定义一个Invariant函数

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);
}

也许我在写废话,但即使在这种情况下,当每个人都告诉我错误时,它会有一些教学价值。