IEnumerator <t>。当前超出MoveNext()== false

时间:2016-11-23 21:12:36

标签: c# .net iterator

我的图表库中有以下代码:

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设置为下一个   元件。

1 个答案:

答案 0 :(得分:3)

如果(w{0,3}\.*[a-z]+\.[a-z]*) 返回Current,则根据接口的合同,未定义MoveNext的值,如其文档中所述。你永远不应该依赖任何给定的行为。只要falseCurrent,您就不应该检查MoveNext的值。

  

如果false通过集合的末尾,则枚举数位于集合中的最后一个元素之后,MoveNext返回MoveNext。当枚举数位于此位置时,对false的后续调用也会返回MoveNext。如果对[{1}}的最后一次调用返回false,则MoveNext未定义。

(注意falseCurrent应该在这种情况下抛出一个异常,但根据我的经验,大多数实现都不打算显式抛出,它们只暴露一个未定义的值;这个改变是反映在较新的IEnumerator界面的文档中。)