IEnumerable <T>против T [] - PullRequest
       41

IEnumerable <T>против T []

21 голосов
/ 08 августа 2010

Я просто понимаю, что, возможно, я все время ошибался, выставляя T[] своим взглядам вместо IEnumerable<T>.

Обычно для такого вида кода:

foreach (var item in items) {}

item должно быть T[] или IEnumerable<T>?

Чем, если мне нужно получить количество предметов, будет ли Array.Count быстрее, чем IEnumerable<T>.Count()?

Ответы [ 7 ]

31 голосов
/ 08 августа 2010

IEnumerable<T> - это, как правило, лучший выбор по причинам, перечисленным в другом месте. Тем не менее, я хочу поднять один пункт о Count(). Квинтин неверен, когда говорит, что сам тип реализует Count(). На самом деле он реализован в Enumerable.Count() как метод расширения, что означает, что другие типы не могут переопределить его для обеспечения более эффективных реализаций.

По умолчанию Count() должен выполнять итерацию по всей последовательности для подсчета элементов. Однако он знает о ICollection<T> и ICollection и оптимизирован для этих случаев. (В .NET 3.5 IIRC он оптимизирован только для ICollection<T>.) Теперь массив реализует это , поэтому Enumerable.Count() откладывается до ICollection<T>.Count и избегает повторения по всей последовательности. Это все еще будет немного медленнее, чем прямой вызов Length, потому что Count() должен обнаружить, что для начала он реализует ICollection<T>, но по крайней мере это все еще O (1).

То же самое относится и к производительности в целом: код JITted вполне может быть несколько сложнее при итерации по массиву, а не по общей последовательности. В основном вы дадите JIT больше информации для игры, и даже сам компилятор C # по-разному обрабатывает массивы для итерации (используя индексатор напрямую).

Однако эти различия в производительности будут несущественными для большинства приложений - я бы определенно использовал более общий интерфейс, пока у меня не будет веской причины не делать этого.

5 голосов
/ 08 августа 2010

Это частично несущественно, но стандартная теория диктует «Программу с интерфейсом, а не с реализацией».С помощью модели интерфейса вы можете изменить фактический передаваемый тип данных, не влияя на вызывающую сторону, если он соответствует тому же интерфейсу.

В отличие от этого, у вас может быть причина для представления массива специально и вкакой случай хотел бы выразить это.

Для вашего примера я думаю, что IEnumerable<T> было бы желательно.Также стоит отметить, что в целях тестирования использование интерфейса может уменьшить количество головной боли, которую вы понесете, если у вас есть определенные классы, которые вам придется создавать постоянно, коллекции в целом не так плохи, но имеют интерфейсный контрактлегко смоделировать - это очень хорошо.

Добавлено для редактирования:
Это более несущественно, поскольку базовый тип данных - это то, что будет реализовывать метод Count(), для массива он должен обращаться к известнымВ общем, я бы не стал беспокоиться о каких-либо накладных расходах метода. См. ответ Джона Скита для объяснения реализации Count().

3 голосов
/ 08 августа 2010

Поскольку класс Array реализует универсальные интерфейсы System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T> и System.Collections.Generic.IEnumerable<T>, я бы использовал IEnumerable, если только вам не нужны эти интерфейсы.

http://msdn.microsoft.com/en-us/library/system.array.aspx

3 голосов
/ 08 августа 2010

T [] (один размер, на основе нуля) также реализует ICollection<T> и IList<T> с IEnumerable<T>.

Поэтому, если вы хотите меньшую связь в вашем приложении, IEnumerable<T> предпочтительнее. Если вы не хотите индексированный доступ внутри foreach .

1 голос
/ 08 августа 2010

Ваше внутреннее чувство правильное, если все, что заботит или должно заботиться о представлении, имеет перечислимое, это все, что ему нужно в своих интерфейсах.

0 голосов
/ 17 августа 2010

Учитывая, что изменение кода из массива в IEnumerable на более позднем этапе легко, но изменить его другим способом нет, я бы пошел с IEnumerable, пока вы не узнаете, что вам нужен небольшой набор преимуществ для возврата массива.

0 голосов
/ 08 августа 2010

Что это логически (концептуально) извне?

Если это массив, вернуть массив. Если единственной точкой является перечисление, верните IEnumerable. В противном случае IList или ICollection могут быть подходящим вариантом.

Если вы хотите предложить множество функциональных возможностей, но не позволяете изменять его, то, возможно, используйте внутренний список и верните ReadonlyList, возвращенный его методом .AsReadOnly ().

...