IEnumerator<T>.当前超出 MoveNext() == false

问题描述 投票:0回答:1

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

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 的所有标准实现,以及具有产量返回的迭代器方法。

该行为是否未指定?

如果不是,正确的表示法是什么?将“当前”保留为上一个,还是设置为默认值(T)?

更新:

我探索了 IEnumerator 对于集合、Linq 扩展以及类型化数组的一些实现:fiddle

在我的理解中,Linq 违反了 IEnumerable 的约定,因为它不会在枚举结束之后在 Current 上抛出异常,而类型化数组也违反了 IEnumerable 的约定,因为它在

IEnumerable<T>.Current
上抛出,并且没有为 指定异常类型IEnumerable.Current.

有人可以澄清一下,文档中所说的“未定义”是什么意思?是否包括抛出未指定的异常:

来自 IEnumerator.Current Property 文档:

在以下任何条件下,当前未定义

  • 在创建枚举器之后,枚举器立即定位在集合中第一个元素之前。在读取 Current 的值之前,必须调用 MoveNext 将枚举器前进到集合的第一个元素。
  • 最后一次调用 MoveNext 返回 false,表示集合结束。
  • 由于集合中发生的更改(例如添加、修改或删除元素),枚举数会失效。 Current 返回相同的对象,直到调用 MoveNext。 MoveNext 将 Current 设置为下一个元素。
c# .net iterator
1个回答
6
投票

如果

Current
返回
MoveNext
,则
false
的值未定义,按照接口合同,如其文档中所述。 你永远不应该依赖任何特定的行为。 当
Current
MoveNext
时,您根本不应该检查
false
的值。

如果

MoveNext
到达了集合的末尾,则枚举数位于集合中最后一个元素之后,并且
MoveNext
返回
false
。当枚举器位于此位置时,对
MoveNext
的后续调用也会返回
false
。如果最后一次调用
MoveNext
返回
false
,则
Current
未定义。

(请注意

IEnumerator
表示
Current
在这种情况下应该抛出异常,但根据我的经验,大多数实现都不会显式抛出异常,它们只是公开未定义的值;此更改反映在较新的
IEnumerator<T> 中) 
接口文档。)

© www.soinside.com 2019 - 2024. All rights reserved.