Возвращение "IList" против "ICollection" против "коллекции" - PullRequest
105 голосов
/ 25 марта 2012

Я не понимаю, какой тип коллекции мне следует возвращать из моих открытых методов и свойств API.

Коллекции, которые я имею в виду: IList, ICollection и Collection.

Всегда ли возврат одного из этих типов предпочтительнее других или это зависит от конкретной ситуации?

Ответы [ 6 ]

128 голосов
/ 25 марта 2012

ICollection<T> - это интерфейс, который предоставляет семантику коллекции, такую ​​как Add(), Remove() и Count.

Collection<T> - это конкретная реализация интерфейса ICollection<T>.

IList<T> по сути ICollection<T> со случайным доступом на основе порядка.

В этом случае вам следует решить, требуется ли для ваших результатов семантика списка, такая как индексация на основе порядка (затем используйте IList<T>), или вам просто нужно вернуть неупорядоченную «сумку» результатов (затем используйте ICollection<T>) .

66 голосов
/ 25 марта 2012

Как правило, вы должны возвращать тип, который является как можно более общим, т. Е. Тип, который достаточно точно знает возвращаемых данных, которые должен использовать потребитель.Таким образом, вы получаете больше свободы для изменения реализации API, не нарушая код, который его использует.

Рассматривайте также интерфейс IEnumerable<T> в качестве возвращаемого типа.Если результат будет повторяться, потребителю не нужно больше.

54 голосов
/ 25 марта 2012

Основное различие между IList<T> и ICollection<T> заключается в том, что IList<T> позволяет получить доступ к элементам через индекс. IList<T> описывает массивоподобные типы. Элементы в ICollection<T> могут быть доступны только через перечисление. Оба позволяют вставлять и удалять элементы.

Если вам нужно только перечислить коллекцию, то IEnumerable<T> предпочтительнее. Он имеет два преимущества перед другими:

  1. Запрещает изменения в коллекции (но не в ссылочных объектах, если они относятся к ссылочному типу).

  2. Он допускает максимально возможное разнообразие источников, включая перечисления, которые генерируются алгоритмически и вообще не являются коллекциями.

Collection<T> - это базовый класс, который в основном полезен для разработчиков коллекций. Если вы представите его в интерфейсах (API), многие полезные коллекции, не производные от него, будут исключены.


Одним из недостатков IList<T> является то, что массивы реализуют его, но не позволяют вам добавлять или удалять элементы (то есть вы не можете изменять длину массива). Исключение будет выдано, если вы вызовете IList<T>.Add(item) для массива. Ситуация несколько разрядилась, так как IList<T> имеет логическое свойство IsReadOnly, которое вы можете проверить, прежде чем пытаться это сделать. Но на мой взгляд, это все еще недостаток дизайна в библиотеке . Поэтому я использую List<T> напрямую, когда требуется возможность добавлять или удалять элементы.

6 голосов
/ 11 ноября 2015

IList<T> - базовый интерфейс для всех общих списков. Так как это упорядоченная коллекция, реализация может принять решение об упорядочении, начиная от отсортированного порядка до порядка вставки. Более того, Ilist имеет свойство Item, которое позволяет методам читать и редактировать записи в списке на основе их индекса. Это позволяет вставлять, удалять значение в / из списка по индексу позиции.

Также, начиная с IList<T> : ICollection<T>, все методы из ICollection<T> также доступны здесь для реализации.

ICollection<T> является базовым интерфейсом для всех общих коллекций. Он определяет размер, перечислители и методы синхронизации. Вы можете добавить или удалить элемент в коллекцию, но не можете выбрать, в какой позиции он находится из-за отсутствия свойства индекса.

Collection<T> обеспечивает реализацию для IList<T>, IList и IReadOnlyList<T>.

Если вы используете более узкий тип интерфейса, например ICollection<T> вместо IList<T>, вы защитите свой код от критических изменений. Если вы используете более широкий тип интерфейса, такой как IList<T>, вы рискуете нарушить изменения кода.

Цитирование из источника ,

ICollection, ICollection<T>: Вы хотите изменить коллекцию или Вы заботитесь о его размере. IList, IList<T>: Вы хотите изменить коллекцию, и вы заботитесь о порядке и / или расположении элементов в коллекции.

4 голосов
/ 25 марта 2012

Возвращение типа интерфейса является более общим, поэтому (без дополнительной информации о вашем конкретном случае использования) я бы склонялся к этому.Если вы хотите предоставить поддержку индексирования, выберите IList<T>, в противном случае будет достаточно ICollection<T>.Наконец, если вы хотите указать, что возвращаемые типы доступны только для чтения, выберите IEnumerable<T>.

И, если вы еще не читали его, Брэд Абрамс и Кшиштоф Квалина написали большую книгу под названием «FrameworkРекомендации по проектированию: условные обозначения, идиомы и шаблоны для многократно используемых библиотек .NET »(вы можете скачать дайджест по ссылке здесь ).

0 голосов
/ 25 марта 2012

Есть некоторые предметы, которые приходят из этого вопроса:

  • интерфейсы против классов
  • какой конкретный класс, из нескольких похожих классов, коллекции, списка, массива?
  • Общие классы в сравнении с коллекциями подпунктов ("дженериков")

Вы можете выделить, что это Object Oriented A.P.I.

интерфейсы против классов

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

И, в конце концов, сделайте плохой дизайн интерфейса, вместо хорошего дизайна класса, который, кстати, в конечном итоге может быть перенесен на хороший дизайн интерфейса ...

В A.P.I. вы увидите много интерфейсов, но не торопитесь с этим, если тебе это не нужно.

В конце концов вы научитесь применять интерфейсы к своему коду.

какой конкретный класс из нескольких похожих классов, коллекции, списка, массива?

В c # (dotnet) есть несколько классов, которые можно поменять местами. Как уже упоминалось, если вам нужно что-то из более специфического класса, такого как «CanBeSortedClass», то сделайте это явно в вашем A.P.I ..

Ваш А.П.И. пользователю действительно нужно знать, что ваш класс можно отсортировать или применить какой-то формат к элементам? Затем используйте «CanBeSortedClass» или «ElementsCanBePaintedClass», в противном случае используйте «GenericBrandClass».

В противном случае используйте более общий класс.

Классы общих коллекций по сравнению с коллекциями подпунктов ("дженериков")

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

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

Имеет ли ваш А.П.И. пользователю понадобится очень специфический тип, одинаковый для всех элементов?

Используйте что-то вроде List<WashingtonApple>.

Ваш А.П.И. пользователю потребуется несколько связанных типов?

Выставьте List<Fruit> для своего А.П., и используйте List<Orange> List<Banana>, List<Strawberry> внутри, где Orange, Banana и Strawberry являются потомками Fruit.

Имеет ли ваш А.П.И. пользователю понадобится коллекция универсальных типов?

Используйте List, где все элементы object (s).

Приветствие.

...