理解扩展ElementAt(索引)

Mob*_*erg 5 c# linq extension-methods

考虑以下代码:

int size = 100 * 1000 * 1000;
var emu = Enumerable.Range(0, size);
var arr = Enumerable.Range(0, size).ToArray();
Run Code Online (Sandbox Code Playgroud)

当我调用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)
Run Code Online (Sandbox Code Playgroud)

并且因为'source'是IEnumerable,所执行的逻辑将是类似的 - 与我看到的直接访问数组的情况相反.

有人可以解释一下:)

SLa*_*aks 12

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

调用ElementAt上的IList<T>(例如阵列)将使用IList<T>的索引器立刻得到所需的索引.(一个O(1)操作)


Jon*_*eet 5

这是在执行时执行的优化.虽然调用没有超载,但它能够检查(使用isas)源是否实际上是IList<T>.如果是,它可以直接转到正确的元素.

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

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