IEnumerable <T> vs T []
Я просто понимаю, что, может быть, я все время ошибался в раскрытии T[]
для моих представлений вместо IEnumerable<T>
.
Обычно для этого типа кода:
foreach (var item in items) {}
item
должен быть T[]
или IEnumerable<T>
?
Чем, если мне нужно будет подсчитать количество элементов, будет ли Array.Count
быстрее над IEnumerable<T>.Count()
?
Ответы
Ответ 1
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).
То же самое относится и к производительности в целом: JIT-код может быть несколько более жестким при повторении по массиву, а не к общей последовательности. В основном вы предоставляете JIT дополнительную информацию, и даже сам компилятор С# обрабатывает массивы по-разному для итерации (напрямую с помощью индексатора).
Однако эти различия в производительности будут несущественными для большинства приложений - я бы определенно пошел с более общим интерфейсом, пока у меня не было повода для этого.
Ответ 2
Это частично несущественно, но стандартная теория диктует "Программу против интерфейса, а не реализацию". С помощью модели интерфейса вы можете изменить фактический тип данных, передаваемый без воздействия на вызывающего, если он соответствует одному и тому же интерфейсу.
Противоположность этому заключается в том, что у вас может быть причина для непосредственного отображения массива и в этом случае хотелось бы выразить это.
Для вашего примера я думаю, что IEnumerable<T>
было бы желательно. Также стоит отметить, что для тестирования с использованием интерфейса можно уменьшить количество головной боли, которое вы понесли бы, если бы у вас были определенные классы, которые вы должны были бы повторно создавать все время, коллекции не так уж плохи в целом, но с интерфейсом вы можете легко насмехаться, очень приятно.
Добавлено для редактирования:
Это более несущественно, потому что базовый тип данных - это то, что будет реализовывать метод Count()
, для массива он должен получить доступ к известной длине, я бы не стал беспокоиться о каких-либо ощутимых накладных расходах метода.
См. ответ Jon Skeet для объяснения реализации Count()
.
Ответ 3
T [] (один размер, основанный на нуле) также реализует ICollection<T>
и IList<T>
с помощью IEnumerable<T>
.
Поэтому, если вы хотите использовать меньшую связь в своем приложении IEnumerable<T>
, предпочтительнее. Если вы не хотите индексировать доступ внутри foreach.
Ответ 4
Так как класс 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
Ответ 5
Ваше чувство кишки правильное, если все взгляды заботятся или должны заботиться о них, имеет перечислимое, что все, что он должен требовать в своих интерфейсах.
Ответ 6
Что это логически (концептуально) извне?
Если это массив, верните массив. Если единственная точка - перечислить, то верните IEnumerable. В противном случае IList или ICollection могут быть доступны.
Если вы хотите предложить множество функциональных возможностей, но не разрешите его изменять, то, возможно, используйте список внутри и верните возвращаемый из него ReadonlyList.AsReadOnly().
Ответ 7
Учитывая, что изменение кода из массива в IEnumerable на более поздний срок является простым, но изменить его другим способом нет, я бы пошел с IEnumerable, пока вы не узнаете, что вам нужен небольшой spead benfit для возврата массива.