2010-07-05 2 views
5

Рассмотрим этот код:Понимание расширения ElementAt (индекс)

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

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

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

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

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

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

ответ

5

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

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

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

+0

Вы можете несколько косвенно отказаться от оптимизации, указав, что ваш пользовательский тип коллекции реализует 'IList ', но реализуйте его явно и/или только когда-либо публиковате свою коллекцию как« IEnumerable '. Это не идеально, но в принципе это оптимизационные «крючки». Если бы вы этого захотели, вы могли бы предоставить настраиваемый интерфейс для каждого настраиваемого метода расширения, который позволяет сценаристу класса переопределить поведение метода расширения, хотя это может немного захлаться. Что-то вроде 'WidgetExtensions.ToggleWidget (этот виджет виджетов) 'и' WidgetExtensions.IToggleWidget '. –

12

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

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

+0

Arh, так что вы говорите мне, что ElementAt перегружен для массивов, списков, Whatnot ..? – Moberg

+1

Это не перегружено. Он использует тип-литье – SLaks

Смежные вопросы