使用代码合约确保收集保持不变
我试图实现方法的后置条件。 我想保证它不会改变内部状态的某个特定部分(我修正了一个bug,因为它曾经这样做过。为了达到目的,我在代码中添加了后置条件)。 我最好的尝试如下:
Contract.Ensures(PropertyA.Collection.Count == Contract.OldValue(PropertyA.Collection).Count);
Contract.Ensures(Contract.ForAll(0, PropertyA.Collection.Count, index => this.PropertyA.Collection[index].Equals(Contract.OldValue(this.PropertyA.Collection)[index])));
此代码的问题是Contract.OldValue(PropertyA.Collection)
在第二行中引起空引用异常。 在第11.8节(http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf)中的代码合同手册中声明,此特定的Contract.ForAll
应与Contract.OldValue
,但另一个过载不。
有没有另外一种方法可以执行检查:PropertyA.Collection中的项目没有改变值,也没有以某种方式重新排序?
你的问题还不清楚,但我期望PropertyA.Collection
和PropertyB.Collection
是引用类型。 Contracts.OldValue()
和引用类型的一个问题是, Contracts.OldValue()
不保存指向的旧对象,而是保存指针本身。
出于这个原因,你的第一份合同将永远是真实的,因为你有效地将价值与自身进行比较。 写它的正确方法是
Contract.Ensures(PropertyA.Collection.Count == Contract.OldValue(PropertyA.Collection.Count));
我不确定你的第二份合同为什么失败。 通常,在尝试比较方法调用前后的集合时,需要将集合保存为可枚举:
Contract.OldValue(PropertyA.Collection.ToList())
// or
Contract.OldValue(PropertyA.Collection.ToArray())
这将评估表达式并将尊敬保存到列表/数组,然后可以对其进行索引。
很抱歉回答这么晚,但代码合同中没有太多活动。
我认为这个问题有两个方面:
1)为了确保条件,正如你所问,我认为可以使用[Pure]函数完成它,并在Contract.Ensures中调用该函数
2)不幸的是,它只能在本地解决问题。 请注意这种情况:
1-调用确保收集条件的函数2-调用确保收集中没有变化的函数3-调用具有(1)中确保的条件的前提条件的函数,
(2)中的[Pure]函数确保集合中未做任何更改不允许CodeContracts推断(1)中的后置条件确保(3)中的前提条件。
我认为CodeContracts应该提供一种功能,以确保对象没有变化,但将对象视为“深层对象”; 可以让你写出类似的东西
提案代码Contract.Ensures(PureArgument(PropertyA.Collection))
由于PureArgument功能应该是CodeContracts的一部分,它可能是一个属性:
提案代码[PureArgument(PropertyA.Collection)]
请注意,CodeContracts可以检查PureArgument属性是否已完成,因为它可以进行深入比较; 检查非常复杂且昂贵(需要深层复制),但可以完成。 但是检查不会是问题,而是检查代码以确保参数没有发生深刻变化,这并非总是可行。
无论如何,我确信像这样的功能将会很好,即使没有检查它是否填充了断言,也没有检查代码以确保参数没有被改变(这比检查断言是全文件更有趣,但是不可能覆盖所有)。
回到问题,确保集合不会更改的解决方案可能是使用新的ReadOnlyCollection(PropertyA.Collection)作为参数,而不是使用PropertyA,但它是代码中的更改。
链接地址: http://www.djcxy.com/p/59603.html上一篇: Using Code Contracts to ensure collection remains unchanged