Consider this code:
int size = 100 * 1000 * 1000;
var emu = Enumerable.Range(0, size);
var arr = Enumerable.Range(0, size).ToArray();
when I call emu.ElementAt(size-10) and arr.ElementAt(size-10) and measure the time the arr is much faster (the array is 0.0002s compared to IEnumerable 0.59s).
As I understand it, the extention method ElementAt() have the signature
public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)
and since the ‘source’ is a IEnumerable the logic carried out would be similar – opposed to what I see where the array is accessed directly.
Could someone please explain this 🙂
This is an optimization performed at execution-time. Although the call isn’t overloaded, it is able to check (using
isoras) whether the source is actually anIList<T>. If it is, it’s able to go directly to the right element.Various other calls do this – notable
Count()which is optimised forICollection<T>and (as of .NET 4) the nongenericICollectioninterface.One of the downsides of extension methods is that all these optimizations have to be performed by the implementation itself – types can’t override anything to “opt in” to optimizing extension methods. That means the optimizations have to all be known by the original implementor 🙁