我正在使用Code Contracts和Code Contracts Editor Extensions VS2010加载项。我有一个实现IEnumerable<T>
接口的类,我已经为GetEnumerator()
方法实现了一个迭代器块。在它上面,我可以看到以下继承的合同:
我理解第一个和第三个合同要求 - GetEnumerator()
必须永远不会返回null,并且绝不能导致副作用。但第二份合同要求意味着什么? Model
和IEnumerator<T>
的{{1}}属性是什么?
编辑:正如Damien_The_Unbeliever在评论中指出的那样,IEnumerable
和IEnumerable<T>
的合同位于单独的文件中,即合同参考大会。使用Reflector,在这两个接口的合同的反汇编中(完整代码为here),您可以看到以下内容:
IEnumerator<T>
有趣的是,[return: Fresh]
[Escapes(true, false), Pure, GlobalAccess(false)]
public IEnumerator GetEnumerator()
{
IEnumerator enumerator;
Contract.Ensures((bool) (Contract.Result<IEnumerator>() != null), null, "Contract.Result<IEnumerator>() != null");
Contract.Ensures((bool) (Contract.Result<IEnumerator>().Model == this.Model), null, "Contract.Result<IEnumerator>().Model == this.Model");
Contract.Ensures((bool) (Contract.Result<IEnumerator>().CurrentIndex == -1), null, "Contract.Result<IEnumerator>().CurrentIndex == -1");
return enumerator;
}
中的额外合同未被编辑扩展显示:
GetEnumerator()
还有一些额外的谜团(例如Contract.Result<IEnumerator>().CurrentIndex == -1
,Fresh
和Escapes
属性。)
答案 0 :(得分:2)
再看一下从C:\ Program Files \ Microsoft \ Contracts \ Contracts.NETFramework \ v4.0 \ mscorlib.Contracts.dll(在我的评论中引用)加载的代码/合约。
我相信您的实施可以安全地忽略它。它似乎与之相关的是它试图定义一个契约,以便(有效地)一旦你使用IEnumerator
对象进行迭代,它将返回一定数量的元素。当对GetEnumerator的调用返回时,这些元素被有效地“快照”,并且对Reset和MoveNext的调用只能迭代同一组元素。
我认为它试图提供一些不变性保证。我不知道我们是否可以自己编写这些类似的合同 - 它使用ContractModel
属性,这个属性似乎没有在任何地方记录,只要我能找到。
关于不可变性等:
我主要在返回的IEnumerator对象上查看MoveNext的合约 - 基本上,它说MoveNxt不能改变Model属性(我们知道GetEnumerator为它分配了相同的Model),以及CurrentIndex属性在0和Model.Length之间变化。在那之后,这只是直觉/猜测。我无法指出合同装配中的任何其他内容,它可以为我提供更多信息。