我的图表库中有以下代码:
while(true) {
using (var i = ancestry.GetAdjacent(current).GetEnumerator())
{
if (!i.MoveNext())
yield break;
if (i.MoveNext())
throw new InvalidOperationException("ancestry graph can only have one adjacent vertex for any given vertex");
// it's a bug, as some enumerators could return null after failed MoveNext().
current = i.Current;
if (isSentinel(current))
yield break;
}
}
此代码适用于IEnumerator的某些实例,而其他实例(.NET中的所有标准实现,以及带有yield返回的迭代器方法)都失败。
这种行为是否未指明?
如果没有,那么正确的符号是什么?将Current保留为previous,或设置为default(T)?
更新:
我已经探讨了IEnumerator的一些实现,用于集合,Linq扩展以及类型化数组:fiddle。
根据我的理解,Linq违反了IEnumerable的合同,因为它没有在枚举结束时抛出Current,并且类型化数组违反了IEnumerable的合同,因为它抛出了IEnumerable<T>.Current
,并且没有为IEnumerable.Current指定的异常类型。
有人可以澄清,它是什么意思&#39; undefined&#39;什么时候在文档中说明?它是否包括抛出未指明的例外:
来自IEnumerator.Current Property文档:
在以下任何条件下,当前未定义: 枚举器位于集合中的第一个元素之前, 在创建枚举数之后立即生效。必须调用MoveNext 将枚举器推进到集合的第一个元素 在读取Current的值之前。最后一次调用MoveNext 返回false,表示集合的结束。该 由于集合中所做的更改,枚举数无效 添加,修改或删除元素。电流返回相同 对象,直到调用MoveNext。 MoveNext将Current设置为下一个 元件。
答案 0 :(得分:3)
如果(w{0,3}\.*[a-z]+\.[a-z]*)
返回Current
,则根据接口的合同,未定义MoveNext
的值,如其文档中所述。你永远不应该依赖任何给定的行为。只要false
为Current
,您就不应该检查MoveNext
的值。
如果
false
通过集合的末尾,则枚举数位于集合中的最后一个元素之后,MoveNext
返回MoveNext
。当枚举数位于此位置时,对false
的后续调用也会返回MoveNext
。如果对[{1}}的最后一次调用返回false
,则MoveNext
未定义。
(注意false
说Current
应该在这种情况下抛出一个异常,但根据我的经验,大多数实现都不打算显式抛出,它们只暴露一个未定义的值;这个改变是反映在较新的IEnumerator
界面的文档中。)