我通过调用IEnumerable<T>.GetEnumerator()
得到了一个枚举器,然后我调用它MoveNext()
直到它返回false,然后访问它的Current
属性。令我惊讶的是,没有抛出异常。
挖掘MSDN,我发现非通用版本will throw if Current
is accessed after MoveNext()
returned false,而通用版本will not。
有人可以解释这种差异吗?
答案 0 :(得分:2)
事实上,这种好奇心已被多次注意到 - 但最终,在MoveNext()
返回false
之后,您应该将Current
的值视为未定义的行为。如果你这样做:这里没有问题。只是:不在这里访问Current
- 那么它是“最后的已知值”与“该类型的默认值”vs“抛出异常”无关紧要
此外,请注意,由于实现引发了异常,因此通用API的实现也完全有可能抛出,并且非泛型API也不会抛出。作为后者的一个例子 - 迭代器块不要抛出:
static void Main()
{
IEnumerator<int> typed = GetInts();
typed.MoveNext();
Console.WriteLine(typed.MoveNext());
int i = typed.Current;
IEnumerator untyped = GetInts();
untyped.MoveNext();
Console.WriteLine(untyped.MoveNext());
object o = untyped.Current;
}
static IEnumerator<int> GetInts()
{
yield return 4;
yield break;
}
答案 1 :(得分:1)
通用枚举器的行为是 undefined ,一切皆有可能,最终由集合类型来定义 undefined 的含义。
但是除了投掷之外,他们可以做一些合理的事情,通用枚举器知道集合对象的类型。所以他们可以返回default(T)
。
非通用枚举器没有那么奢侈,他们只能返回null或new object()
。事实上,ArrayList具有为此目的保留静态对象的代码。但实际上并没有使用它,看起来他们在可用性测试后改变了主意。返回任何一个都会使客户端代码失败并出现非常令人不快的异常,NullReferenceException或InvalidCastException。在这些集合的正常使用中也可以引发异常,因此对于事故的实际原因几乎没有暗示。所以他们没有,他们会抛出InvalidOperationException。