Подтвердить что ты не робот

IEnumerable <T> vs T []

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

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

foreach (var item in items) {}

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

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

4b9b3361

Ответ 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 для возврата массива.