В чем разница между List (of T) и Collection (of T)?

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

Ответ 1

Collection<T> - настраиваемая обертка вокруг IList<T>. Пока IList<T> не запечатан, он не предоставляет никаких точек настройки. Collection<T> методы по умолчанию делегируются стандартным методам IList<T>, но их можно легко переопределить, чтобы делать то, что вы хотите. Также возможно подключать события внутри Collection<T>, которые, как я полагаю, не могут быть выполнены с помощью IList.

Короче говоря, гораздо проще продлить его после факта, что потенциально может означать гораздо меньше рефакторинга.

Ответ 2

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

Collection<T> служит базовый класс для пользовательских коллекций (хотя он может использоваться напрямую).

Рассмотрите возможность использования Collection<T> в вашем коде, если вам не нужны специальные функции List<T>.

Выше приведены только рекомендации.

[Адаптировано из: Framework Design Guidelines, Second Edition]

Ответ 3

В С# существует три понятия для представления мешка объектов. В порядке увеличения возможностей они:

  • Перечислимый - неупорядоченный, немодифицируемый
  • Коллекция - может добавлять/удалять элементы
  • Список - позволяет элементам иметь заказ (доступ и удаление по индексу)

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

Коллекция - модифицируемый набор. Вы можете добавлять и удалять объекты из набора, вы также можете получить количество элементов в наборе. Но по-прежнему нет порядка, и потому, что нет порядка: нет доступа к элементу по индексу, и нет способа сортировки.

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

На самом деле, глядя на интерфейсы для них, они строят друг на друга:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

При объявлении переменных или параметров метода вы должны выбрать

  • IEnumerable
  • ICollection
  • IList

на основе концептуально вам нужно сделать набор объектов.

Если вам просто нужно что-то сделать для каждого объекта в списке, вам нужно только IEnumerable:

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

Вам все равно, сохраняются ли пользователи в List<T>, Collection<T>, Array<T> или что-то еще. Вам нужен только интерфейс IEnumerable<T>.

Если вам нужно иметь возможность добавлять, удалять или подсчитывать элементы в наборе, используйте Коллекция:

ICollection<User> users = new Collection<User>();
users.Add(new User());

Если вам нужен порядок сортировки и нужно, чтобы заказ был правильным, используйте Список:

IList<User> users = FetchUsers(db);

В виде диаграммы:

| Feature                | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items      | X              | X              | X        |
|                        |                |                |          |
| Adding items           |                | X              | X        |
| Removing items         |                | X              | X        |
| Count of items         |                | X              | X        |
|                        |                |                |          |
| Accessing by index     |                |                | X        |
| Removing by indexx     |                |                | X        |
| Getting index of item  |                |                | X        |

List<T> и Collection<T> в System.Collections.Generic - это два класса, которые реализуют эти интерфейсы; но они не являются единственными классами:

  • ConcurrentBag<T> - это упорядоченный пакет объектов (IEnumerable<T>)
  • LinkedList<T> - это мешок, в котором вам не разрешено обращаться к элементам по индексу (ICollection); но вы можете произвольно добавлять и удалять элементы из коллекции.
  • SynchronizedCollection<T> в упорядоченной коллекции, где вы можете добавлять/удалять элементы по индексу

Итак, вы можете легко изменить:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

TL;DR

  • Перечислимый - доступ к элементам, неупорядоченный, немодифицируемый
  • Коллекция - может быть изменена (добавлена, удалена, подсчитана)
  • Список - можно получить доступ по индексу

Выберите нужную вам концепцию, затем используйте соответствующий класс.

Ответ 4

List<T> - очень часто просматриваемый контейнер, потому что он настолько универсален (с множеством удобных методов, таких как Sort, Find и т.д.) - но не имеет точек расширения, если вы хотите переопределить любой из поведение (например, проверьте элементы вставки).

Collection<T> является оберткой вокруг любого IList<T> (по умолчанию List<T>) - он имеет точки расширения (методы virtual), но не так много поддерживающих методов, как Find. Из-за косвенности она немного медленнее, чем List<T>, но не намного.

С LINQ дополнительные методы в List<T> становятся менее важными, поскольку LINQ-to-Objects имеют тенденцию предоставлять их в любом случае... например First(pred), OrderBy(...) и т.д.

Ответ 5

Список быстрее.

Сделайте, например,

private void button1_Click(object sender, EventArgs e)
{
  Collection<long> c = new Collection<long>();
  Stopwatch s = new Stopwatch();
  s.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    c.Add(i);
  }
  s.Stop();
  MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());

  List<long> l = new List<long>();
  Stopwatch s2 = new Stopwatch();
  s2.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    l.Add(i);
  }
  s2.Stop();
  MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());


}

на моей машине List<> почти в два раза быстрее.

Edit

Я не понимаю, почему люди это делают. Как на моем рабочем компьютере, так и на моей домашней машине код List < > на 80% быстрее.

Ответ 6

Список представляет собой коллекцию, в которой важна последовательность элементов. Он также поддерживает методы s.a. Сортировка и поиск. Сбор представляет собой более общую структуру данных, которая делает меньше предположений относительно данных, а также поддерживает меньшее количество методов для ее обработки. Если вы хотите открыть пользовательскую структуру данных, вам, вероятно, следует расширить коллекцию. Если вам нужно манипулировать данными без публикации структуры данных, список, вероятно, является более удобным способом.

Ответ 7

Это один из тех вопросов в школе. Коллекция T - своего рода реферат; может быть реализация по умолчанию (я не парень .net/С#), но коллекция будет иметь основные операции, такие как добавление, удаление, итерация и т.д.

Список T подразумевает некоторые особенности этих операций: add должен принимать постоянное время, remove должно занимать время, пропорциональное количеству элементов, getfirst должно быть временным. В общем, List - это своего рода коллекция, но Collection не обязательно является своего рода списком.

Ответ 8

Hanselman Speaks: "Collection<T> выглядит как список, и он даже имеет List<T> внутри. КАЖДЫЙ один метод делегирует внутренний List<T>. Он включает защищенное свойство, которое предоставляет List<T>."

EDIT: Collection<T> не существует в System.Generic.Collections.NET 3.5. Если вы перейдете с .NET 2.0 на 3.5, вам нужно будет изменить какой-то код, если вы используете много объектов Collection<T>, если я не пропущу что-то очевидное...

EDIT 2: Collection<T> теперь находится в пространстве имен System.Collections.ObjectModel в .NET 3.5. Файл справки говорит следующее:

"Пространство имен System.Collections.ObjectModel содержит классы, которые могут использоваться как коллекции в объектной модели библиотеки многократного использования. Используйте эти классы, когда свойства или методы возвращают коллекции."

Ответ 9

Все эти интерфейсы наследуются от IEnumerable, которые вы должны убедиться, что понимаете. Этот интерфейс в основном позволяет использовать класс в инструкции foreach (в С#).

  • ICollection - это самый простой из перечисленных вами интерфейсов. Это перечислимый интерфейс, поддерживающий Count, и об этом.
  • IList - это все, что есть ICollection, но также поддерживает добавление и удаление элементов, извлечение элементов по индексу и т.д. Это наиболее часто используемый интерфейс для "списков объектов", который ясен.
  • IQueryable - это перечислимый интерфейс, поддерживающий LINQ. Вы всегда можете создать IQueryable из IList и использовать LINQ to Objects, но вы также найдете IQueryable, используемый для отсроченного выполнения операторов SQL в LINQ to SQL и LINQ to Entities.
  • IDictionary - другое животное в том смысле, что оно является отображением уникальных ключей к значениям. Это также перечислимо тем, что вы можете перечислить пары ключ/значение, но в противном случае оно выполняет другую цель, чем другие, которые вы указали.

Ответ 10

Согласно MSDN, List (Of T).Add - это "операция O (n)" (когда "Capacity" превышена), а Collection (Of T).Add всегда "операция O (1)". Это было бы понятно, если List реализован с использованием массива и коллекции связанного списка. Однако, если бы это было так, можно было бы ожидать Collection (Of T).Item быть "операцией O (n)". Но - это - нет!?! Collection (Of T).Item - это "операция O (1)", как и List (Of T).Item.

Кроме того, "tuinstoel" "Dec 29 '08 at 22:31" сообщение выше, тесты скорости заявлений показывают List (Of T).Add, чтобы быть быстрее, чем Collection (Of T).Add, который я воспроизвел с длинными и строковыми. Хотя я только получил ~ 33% быстрее против его заявленных 80%, согласно MSDN, это должно было быть наоборот и "n" раз!?!

Ответ 11

Оба реализуют одни и те же интерфейсы, поэтому они будут вести себя одинаково. Возможно, они реализованы по-разному внутри, но это должно быть проверено.

Единственными реальными различиями, которые я вижу, являются пространства имен и тот факт, что Collection<T> отмечен ComVisibleAttribute(false), поэтому COM-код не может его использовать.

Ответ 12

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

* = present
o = partially present

Property/Method   Collection<T>   List<T>
----------------------------------------------
Add()                *              *
AddRange()                          *
AsReadOnly()                        *
BinarySearch()                      *
Capacity                            *
Clear()              *              *
Contains()           *              *
ConvertAll()                        *
CopyTo()             o              *
Count                *              *
Equals()             *              *
Exists()                            *
Find()                              *
FindAll()                           *
FindIndex()                         *
FindLast()                          *
FindLastIndex()                     *
ForEach()                           *
GetEnumerator()      *              *
GetHashCode()        *              *
GetRange()                          *
GetType()            *              *
IndexOf()            o              *
Insert()             *              *
InsertRange()                       *
Item()               *              *
LastIndexOf()                       *
New()                o              *
ReferenceEquals()    *              *
Remove()             *              *
RemoveAll()                         *
RemoveAt()           *              *
RemoveRange()                       *
Reverse()                           *
Sort()                              *
ToArray()                           *
ToString()           *              *
TrimExcess()                        *
TrueForAll()                        *