Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用代码契约确保集合保持不变_C#_Code Contracts_Design By Contract - Fatal编程技术网

C# 使用代码契约确保集合保持不变

C# 使用代码契约确保集合保持不变,c#,code-contracts,design-by-contract,C#,Code Contracts,Design By Contract,我试图实现一个方法的post条件。我想保证它不会改变内部状态的某个特定部分(我修复了一个bug,就像它以前那样。为了避免重复,我在代码中添加了post条件)。我的最佳尝试如下: Contract.Ensures(PropertyA.Collection.Count == Contract.OldValue(PropertyA.Collection).Count); Contract.Ensures(Contract.ForAll(0, PropertyA.Collection.Count, in

我试图实现一个方法的post条件。我想保证它不会改变内部状态的某个特定部分(我修复了一个bug,就像它以前那样。为了避免重复,我在代码中添加了post条件)。我的最佳尝试如下:

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节()中的代码合同手册中规定,此特定的合同。对于所有,应与合同.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]函数来实现,并在合同中调用此函数。确保

2) 不幸的是,它只能在局部解决问题。注意这种情况:

1-调用一个函数,该函数确保反收集条件 2-调用一个函数,确保集合中没有更改 3-调用以(1)中确保的条件为前提的函数

(2)中的[Pure]函数用于确保集合中未做任何更改,但不允许CodeContracts推断(1)中的后条件确保(3)中的前提条件

我认为CodeContracts应该提供一种功能来确保对象没有变化,而是将对象作为“深层对象”;可以让你写像这样的东西

提案代码 Contract.conference(PureArgument(PropertyA.Collection))

由于功能PureArgument应该是CodeContracts的一部分,因此它可以是一个属性:

提案代码 [PureArgument(PropertyA.Collection)]

注意,CodeContracts可以检查PureArgument属性是否满足,因为它可以进行深度比较;检查起来非常复杂和昂贵(它需要一个深度拷贝),但这是可以做到的。但是检查不是问题,而是检查代码以确保参数没有发生深刻的更改,这并不总是可能的

无论如何,我相信这样的特性会很好,即使不检查断言是否完整,也不检查代码以确保参数没有更改(这比检查断言是否完整更有趣,但根本无法涵盖)


回到问题上来,确保集合不会更改的解决方案可以是使用新的ReadOnlyCollection(PropertyA.collection)作为参数,而不是使用PropertyA,但这是代码中的一个更改。

我可能会编写一个测试,而不是使用前置/后置条件来跟踪回归是否不会再次回归。这样,您仍然会注意到,而且您也不会因为每次都要检查而给来电者带来负担。ο。呼叫者没有义务检查post条件。被调用的方法保证PropertyA的集合不受影响。我指的是性能负担,而不是调用方每次都需要做些什么:-)@οοοа:啊,这可能是调试版本的问题,但不是发布版本的问题。代码契约不会在应用程序的发布版本中编译。幸运的是,使用此契约的方法只在应用程序的特定部分执行一次(不是连续多次),因此在我们的情况下,性能负担可以被认为是可以接受的。但我同意你的看法,考虑到这一点是明智的。