我想静态验证以下代码合同的基于数组的堆栈的部分实现。方法Pop()
使用纯函数IsNotEmpty()
来确保后续的数组访问将位于/高于下限。静态验证器失败并建议我添加前提条件Contract.Requires(0 <= this.top)
。在C#代码合同中使用纯函数时的静态验证限制?
任何人都可以解释为什么验证者无法证明该数组访问是有效的下限给定合同IsNotEmpty()
?
起初我认为Contract.Requires(IsNotEmpty())
方法可能不正确,因为子类可以覆盖IsNotEmpty()
。但是,如果我将该类标记为sealed
,验证程序仍然无法证明该数组访问是有效的。
更新:如果我将IsNotEmpty()
更改为只读属性,则验证将按预期成功。这引发了一个问题:如何/为什么只读属性和纯函数的处理方式不同?
class StackAr<T>
{
private T[] data;
private int capacity;
/// <summary>
/// the index of the top array element
/// </summary>
private int top;
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(data != null);
Contract.Invariant(top < capacity);
Contract.Invariant(top >= -1);
Contract.Invariant(capacity == data.Length);
}
public StackAr(int capacity)
{
Contract.Requires(capacity > 0);
this.capacity = capacity;
this.data = new T[capacity];
top = -1;
}
[Pure]
public bool IsNotEmpty()
{
return 0 <= this.top;
}
public T Pop()
{
Contract.Requires(IsNotEmpty());
//CodeContracts: Suggested precondition:
//Contract.Requires(0 <= this.top);
T element = data[top];
top--;
return element;
}
}
个人而言,我是一个对代码合同有点失望... – ChaosPandion 2010-09-12 16:37:53
ChaosPandion,有什么令人失望的? – 2010-09-12 17:17:15
即使当类没有标记为'sealed'时,继承类*不能*覆盖'IsNotEmpty',因为它没有标记为'virtual',所以在那里没有问题。 – 2010-09-12 17:53:04