我原本以为为实现的空集合执行以下代码IEnumerable<T>会抛出异常:
var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
var type = enumerator.Current.GetType(); // Surely should throw?
Run Code Online (Sandbox Code Playgroud)
因为集合是空的,所以访问IEnumerator.Current无效,我本来期望一个例外.但是,没有例外List<T>.
这是允许的文档IEnumerator<T>.Current,其中指出Current在以下任何条件下未定义:
(我假设"未能抛出异常"可归类为"未定义行为"......)
但是,如果你做同样的事情,但使用一个IEnumerable,你会得到一个例外.此行为由文档IEnumerator.Current指定,其中指出:
我的问题是:为什么会有这种差异?我不知道有一个很好的技术原因吗?
这意味着看起来相同的代码可以表现得非常不同,具体取决于它是否正在使用,IEnumerable<T>或者IEnumerable如下面的程序所示(注意代码内部showElementType1()和showElementType1()相同):
using System;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApplication2
{
class Program
{
public static void Main()
{
var list = new List<int>();
showElementType1(list); // Does not throw an exception.
showElementType2(list); // Throws an exception.
}
private static void showElementType1(IEnumerable<int> collection)
{
var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
var type = enumerator.Current.GetType(); // No exception thrown here.
Console.WriteLine(type);
}
private static void showElementType2(IEnumerable collection)
{
var enumerator = collection.GetEnumerator();
enumerator.MoveNext();
var type = enumerator.Current.GetType(); // InvalidOperationException thrown here.
Console.WriteLine(type);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Pat*_*man 22
问题IEnumerable<T>在于Current类型T.而不是抛出一个异常,default(T)则返回(它是从设置MoveNextRare).
使用IEnumerable时没有类型,也无法返回默认值.
实际问题是你没有检查返回值MoveNext.如果它返回false,你不应该打电话Current.例外是可以的.我认为,他们发现更方便地返回default(T)的IEnumerable<T>情况.
异常处理带来开销,返回default(T)不会(那么多).也许他们只是认为Current在IEnumerable(他们不知道类型)的情况下从房产返回没有任何用处.这个问题在IEnumerable<T>使用时"解决"了default(T).
出于性能原因,生成的枚举器的Current属性保持非常简单 - 它只返回生成的"当前"支持字段的值.
这可能指向异常处理的开销方向.或者验证值的必要额外步骤current.
他们实际上只是挥动责任foreach,因为这是调查员的主要用户:
在浩瀚广大普查员的相互作用是foreach循环它已经警惕在这两种状态的访问当前的形式,所以这将是浪费的燃烧多余的CPU周期,每次迭代检查,几乎没有人会遇到这些状态.