IEnumerator.Current和IEnumerator <t> .Current </t>的异常抛出行为

时间:2013-10-21 08:22:52

标签: c# ienumerator

我通过调用IEnumerable<T>.GetEnumerator()得到了一个枚举器,然后我调用它MoveNext()直到它返回false,然后访问它的Current属性。令我惊讶的是,没有抛出异常。

挖掘MSDN,我发现非通用版本will throw if Current is accessed after MoveNext() returned false,而通用版本will not

有人可以解释这种差异吗?

2 个答案:

答案 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。