Возвращение 'IList' против 'ICollection' vs 'Collection'
Я смущен о том, какой тип коллекции должен возвращать из моих общедоступных методов и свойств API.
Коллекции, которые я имею в виду, это IList
, ICollection
и Collection
.
Является ли возврат одного из этих типов предпочтительным для других или зависит от конкретной ситуации?
Ответы
Ответ 1
Как правило, вы должны вернуть тип, который является настолько общим, насколько это возможно, то есть тот, который знает только достаточное количество возвращаемых данных, которые потребитель должен использовать. Таким образом, у вас есть большая свобода для изменения реализации API, не нарушая код, который его использует.
Рассмотрим также интерфейс IEnumerable<T>
как возвращаемый тип. Если результат будет только повторен, потребитель не нуждается в большем.
Ответ 2
ICollection<T>
- это интерфейс, который предоставляет семантику коллекции, такую как Add()
, Remove()
и Count
.
Collection<T>
- это конкретная реализация интерфейса ICollection<T>
.
IList<T>
по существу является ICollection<T>
со случайным доступом на основе порядка.
В этом случае вы должны решить, нужны ли результаты для семантики списка, например, индексирование на основе заказа (затем используйте IList<T>
), или вам просто нужно вернуть неупорядоченный "пакет" результатов (затем используйте ICollection<T>
).
Ответ 3
Основное различие между IList<T>
и ICollection<T>
заключается в том, что IList<T>
позволяет вам обращаться к элементам через индекс. IList<T>
описывает типы, подобные массиву. Элементы в ICollection<T>
могут быть доступны только через перечисление. Оба позволяют вставлять и удалять элементы.
Если вам нужно только перечислить коллекцию, то предпочтительнее использовать IEnumerable<T>
. Он имеет два преимущества перед другими:
-
Он запрещает изменения в коллекции (но не ссылается на объекты, если элементы являются ссылками).
-
Он позволяет использовать максимально возможное множество источников, включая перечисления, которые генерируются алгоритмически и вообще не являются коллекциями.
Collection<T>
- базовый класс, который в основном полезен разработчикам коллекций. Если вы откроете его в интерфейсах (API), многие полезные коллекции, не вытекающие из него, будут исключены.
Одним из недостатков IList<T>
является то, что массивы реализуют его, но не позволяют добавлять или удалять элементы (т.е. вы не можете изменить длину массива). Исключение будет вызываться, если вы вызываете IList<T>.Add(item)
в массиве. Ситуация несколько разряжена, поскольку IList<T>
имеет логическое свойство IsReadOnly
, которое вы можете проверить, прежде чем пытаться это сделать. Но в моих глазах это все еще недостаток дизайна в библиотеке. Поэтому я использую List<T>
напрямую, когда требуется добавить или удалить элементы.
Ответ 4
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>
: вы хотите изменить коллекцию и заботиться о упорядочении и/или позиционировании элементов в коллекции.
Ответ 5
Возвращение типа интерфейса более общее, поэтому (не имея дополнительной информации о вашем конкретном случае использования), я бы склонялся к этому. Если вы хотите открыть поддержку индексирования, выберите IList<T>
, иначе ICollection<T>
будет достаточно. Наконец, если вы хотите указать, что возвращаемые типы являются только для чтения, выберите IEnumerable<T>
.
И, если вы еще не прочитали его раньше, Брэд Абрамс и Кшиштоф Квалина написал замечательную книгу под названием "Руководства по дизайну рамок: условности, идиомы и шаблоны для многоразовых библиотек .NET" (вы можете загрузить дайджест из здесь).
Ответ 6
Есть некоторые темы, которые исходят из этого вопроса:
- интерфейсы и классы
- какой конкретный класс, из нескольких одинаковых классов, коллекции, списка, массива?
- Коллекции общих классов и подэлементов ( "generics" )
Вы можете выделить, что его Object Oriented A.P.I.
интерфейсы и классы
Если у вас нет большого опыта работы с интерфейсами, я рекомендую придерживаться классов.
Я вижу много раз, когда разработчики прыгают на интерфейсы, даже если это не обязательно.
И, закончив плохое проектирование интерфейса, а не хороший дизайн класса,
который, кстати, в конечном итоге может быть перенесен на хороший дизайн интерфейса...
В A.P.I вы увидите много интерфейсов, но не спешите с ним,
если вам это не нужно.
В конечном итоге вы узнаете, как применять интерфейсы к вашему коду.
, какой конкретный класс, из нескольких одинаковых классов, сбор, список, массив?
Существует несколько классов в С# (dotnet), которые могут быть взаимозаменяемы. Как уже упоминалось, если вам нужно что-то из более определенного класса, например "CanBeSortedClass", тогда сделайте его явным в вашем A.P.I..
Является ли ваш A.P.I. пользователь действительно должен знать, что ваш класс может быть отсортирован или применить какой-то формат к элементам? Затем используйте "CanBeSortedClass" или "ElementsCanBePaintedClass",
в противном случае используйте "GenericBrandClass".
В противном случае используйте более общий класс.
Коллекции общих коллекций и подэлементов ( "generics" )
Вы обнаружите, что существуют классы, содержащие другие элементы,
и вы можете указать, что все элементы должны быть определенного типа.
Общие Коллекции - это те классы, которые вы можете использовать одну и ту же коллекцию,
для нескольких приложений кода, без необходимости создавать новую коллекцию,
для каждого нового типа подтипа, например: Collection.
Является ли ваш A.P.I. пользователю нужен очень специфический тип, такой же для всех элементов?
Используйте что-то вроде List<WashingtonApple>
.
Является ли ваш A.P.I. пользователю понадобится несколько связанных типов?
Откройте List<Fruit>
для вашего A.P.I. и используйте List<Orange>
List<Banana>
, List<Strawberry>
внутри, где Orange
, Banana
и Strawberry
являются потомками из Fruit
.
Является ли ваш A.P.I. пользователю понадобится общий набор типов?
Используйте List
, где все элементы object
(s).
Приветствия.