В чем разница между списком (из T) и коллекцией (из T)? - PullRequest
83 голосов
/ 30 декабря 2008

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

Ответы [ 12 ]

61 голосов
/ 04 февраля 2015

В C # есть три концепции для представления пакета объектов. В порядке увеличения возможностей, они:

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

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

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

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

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

  • 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);

ТЛ; др

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

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

48 голосов
/ 30 декабря 2008

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

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

42 голосов
/ 30 декабря 2008

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

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

Подумайте об использовании Collection<T> в своем коде, если вам не нужны особые функции List<T>.

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

[Адаптировано из: Руководства по разработке структуры, второе издание]

37 голосов
/ 30 декабря 2008

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

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

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

12 голосов
/ 30 декабря 2008

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

Например,

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<> почти в два раза быстрее.

Редактировать

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

11 голосов
/ 30 декабря 2008

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

4 голосов
/ 07 ноября 2013

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

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

4 голосов
/ 06 августа 2012

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

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

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

РЕДАКТИРОВАТЬ: 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 содержит классы, которые можно использовать в качестве коллекций в объектной модели библиотеки многократного использования. Используйте эти классы, когда свойства или методы возвращают коллекции."

4 голосов
/ 30 декабря 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...