理解扩展ElementAt(索引)

时间:2010-07-05 14:04:35

标签: c# linq extension-methods

考虑以下代码:

int size = 100 * 1000 * 1000;
var emu = Enumerable.Range(0, size);
var arr = Enumerable.Range(0, size).ToArray();

当我调用emu.ElementAt(size-10)和arr.ElementAt(size-10)并测量arr的时间要快得多(与IEnumerable 0.59s相比,数组为0.0002s)。

据我了解,扩展方法ElementAt()具有签名

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)

由于'source'是一个IEnumerable,所执行的逻辑将是相似的 - 与我所看到的直接访问数组的地方相反。

有人可以解释一下:)

2 个答案:

答案 0 :(得分:12)

ElementAt上调用IEnumerable<T>将遍历项目,直到达到所需的索引。 (一个O(n)操作)

ElementAt(例如数组)上调用IList<T>将使用IList<T>的索引器立即获得所需的索引。 (一个O(1)操作)

答案 1 :(得分:5)

这是在执行时间执行的优化。虽然调用未重载,但可以检查(使用isas)源是否实际为IList<T>。如果是,它就能直接进入正确的元素。

其他各种调用都是这样做的 - 值得注意的是Count(),它针对ICollection<T>和(从.NET 4开始)非通用ICollection接口进行了优化。

扩展方法的一个缺点是所有这些优化都必须由实现本身执行 - 类型不能覆盖任何“选择”优化扩展方法。这意味着原始实现者必须知道优化:(