Понимание расширения ElementAt (index) - PullRequest
5 голосов
/ 05 июля 2010

Рассмотрим этот код:

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

когда я вызываю emu.ElementAt (размер-10) и arr.ElementAt (размер-10) и измеряю время, когда arr намного быстрее (массив равен 0,0002 с по сравнению с IEnumerable 0,59 с).

Насколько я понимаю, метод расширения ElementAt () имеет подпись

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

и поскольку «источник» является IEnumerable, выполняемая логика будет аналогична - в отличие от того, что я вижу, когда к массиву обращаются напрямую.

Может кто-нибудь, пожалуйста, объясните это:)

Ответы [ 2 ]

12 голосов
/ 05 июля 2010

Вызов ElementAt на IEnumerable<T> будет циклически проходить по пунктам, пока не достигнет желаемого индекса.(Операция O (n))

Вызов ElementAt для IList<T> (например, массива) будет использовать индексатор IList<T> для немедленного получения нужного индекса.(Операция O (1))

5 голосов
/ 05 июля 2010

Это оптимизация, выполненная в время выполнения . Хотя вызов не перегружен, он может проверить (используя is или as), является ли источник на самом деле IList<T>. Если это так, он может перейти непосредственно к нужному элементу.

Различные другие вызовы делают это - примечательный Count(), оптимизированный для ICollection<T> и (начиная с .NET 4) неуниверсальный интерфейс ICollection.

Один из недостатков методов расширения заключается в том, что все эти оптимизации должны выполняться самой реализацией - типы не могут переопределить что-либо, чтобы «включить» оптимизацию методов расширения. Это означает, что все оптимизации должны быть известны исходному разработчику: (

...