2012-03-24 3 views
90

Я смущен о том, какой тип коллекции я должен вернуть из своих общедоступных методов и свойств API.Возвращение 'IList' vs 'ICollection' vs 'Collection'

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

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

+4

дубликат: http: // stackoverflow.com/questions/271710/collectiont-versus-listt-what-should-you-use-on-your-interfaces – Robbie

+0

также: http://stackoverflow.com/questions/4455428/difference-between-iqueryable-icollection-ilist- idictionary-interface – nathanchere

ответ

56

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

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

+15

Но также рассмотрите ICollection , который расширяет IEnumerable , чтобы предоставить дополнительные утилиты, включая свойство Count. Это может быть полезно, потому что вы можете определить длину последовательности, не пересекая последовательность несколько раз. – retrodrone

+8

@retrodrone: На самом деле реализация метода 'Count' проверяет фактический тип коллекции, поэтому для некоторых известных типов, таких как массивы и' ICollection', будут использоваться свойства 'Length' или' Count', даже если вы поставите их как 'IEnumerable'. – Guffa

+0

@ Guffa, огромное спасибо за информацию! – retrodrone

115

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

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

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

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

+2

+1 для хорошего ответа. Тем не менее, я бы рекомендовал добавить несколько заметок об общем принципе абстракции и почему он предпочитает возвращать типы интерфейсов, а не конкретные типы классов. –

+4

'Коллекция ' реализует 'IList ' и не только 'ICollection '. – CodesInChaos

+36

Все коллекции в .Net упорядочены, потому что упорядочен 'IEnumerable ''. Что отличает 'IList ' от 'ICollection ' является то, что он предлагает членам работать с индексами. Например, 'list [5]' работает, но 'collection [5]' не будет компилироваться. – svick

48

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

+0

[Code Analysis (и FxCop) рекомендует] (http://stackoverflow.com/q/271710/1497596), что при возврате конкретной общей коллекции необходимо вернуть одно из следующих значений: 'Collection',' ReadOnlyCollection' или ' KeyedCollection'. И этот «Список» не должен возвращаться. – DavidRR

+0

@DavidRR: Часто полезно передать список методу, который должен добавить или удалить элементы. Если вы введете параметр как «IList », нет способа гарантировать, что метод не будет вызываться с параметром array. –

3

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

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

+0

+1. Хороший материал для чтения. –

+0

'IEnumerable ' только для чтения? Конечно, но при перенастройке в контексте репозитория даже после выполнения ToList не является потокобезопасным. Проблема в том, что исходный источник данных получает GC, а затем IEnumarble.ToList() не работает в многопоточном контексте. Он работает на линейной основе, потому что GC вызывается после того, как вы выполняете работу, но используя 'async' теперь дни в 4.5+ IEnumarbale становится шариковой болью. – ppumkin

-5

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

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

Вы можете подчеркнуть, что сво объектно-ориентированного A.P.I.

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

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

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

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

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

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

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

Имеет ли ваш A.P.I. пользователь действительно должен знать, что ваш класс может быть отсортирован или применить какой-то формат к элементам? Затем используйте «CanBeSortedClass» или «ElementsCanBePaintedClass», , иначе используйте «GenericBrandClass».

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

Общие классы коллекций против подпункта («дженериков») коллекции

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

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

Есть ли у вас A.P.I. пользователю нужен очень специфический тип, такой же для всех элементов?

Используйте что-то наподобие List<WashingtonApple>.

Есть ли у вас A.P.I. пользователю понадобится несколько родственных типов?

Expose List<Fruit> для A.P.I., и использовать List<Orange>List<Banana>, List<Strawberry> внутри, где Orange, Banana и Strawberry являются потомками Fruit.

Есть ли у вас A.P.I. пользователю понадобится коллекция универсального типа?

Использовать List, где все предметы object (s).

Cheers.

+6

«Если у вас нет большого опыта работы с интерфейсами, я рекомендую придерживаться классов». Это нехороший совет. Это как сказать, если есть что-то, чего вы не знаете, просто держитесь подальше от него. Интерфейсы чрезвычайно мощные и поддерживают концепцию «Программа для абстракций против конкреций». Они также достаточно мощны для проведения модульного тестирования из-за возможности обмена типами через mocks. Существует множество других оснований для использования интерфейсов за пределами этих комментариев, поэтому, пожалуйста, обязательно исследуйте их. – atconway

+0

@atconway Я регулярно использую интерфейсы, но, поскольку многие концепции, его мощный инструмент, его можно легко смешивать. И, иногда, разработчику может не понадобиться. Мое предложение не было «никогда не интерфейсы», мое предложение было «в этом случае, вы можете пропустить интерфейсы. Узнайте об этом, и вы можете получить лучшее из них позже». Приветствия. – umlcat

+1

Я рекомендую всегда программировать интерфейс. Это помогает поддерживать слабосвязанный код. – mac10688

6

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>, вам больше угрожает нарушение изменений кода.

Цитирование из source,

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

Смежные вопросы