Возвращение "IList" против "ICollection" против "Collection"

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

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

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

6 ответов

Решение

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

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

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

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

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

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

Основное различие между 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> непосредственно, когда требуется возможность добавлять или удалять элементы.

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>: Вы хотите изменить коллекцию, и вы заботитесь о порядке и / или расположении элементов в коллекции.

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

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

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

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

Вы можете подчеркнуть, что это объектно-ориентированный API

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

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

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

В API вы увидите много интерфейсов, но не торопитесь с этим, если вам это не нужно.

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

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

В C# (dotnet) есть несколько классов, которые можно поменять местами. Как уже упоминалось, если вам нужно что-то из более определенного класса, такого как "CanBeSortedClass", то сделайте это явным образом в своем API.

Ваш пользователь API действительно должен знать, что ваш класс может быть отсортирован, или применить некоторый формат к элементам? Затем используйте "CanBeSortedClass" или "ElementsCanBePaintedClass", в противном случае используйте "GenericBrandClass".

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

Общие классы коллекций и коллекции подэлементов ("дженерики")

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

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

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

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

Вашему пользователю API понадобится несколько связанных типов?

разоблачать List<Fruit> для вашего API, и использовать List<Orange>List<Banana>, List<Strawberry> внутри, где Orange, Banana а также Strawberry являются потомками из Fruit,

Вашему пользователю API понадобится универсальная коллекция типов?

использование Listгде все предметы object (Ы).

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

Другие вопросы по тегам