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


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

12 78

12 ответов:

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

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

в C# существует три понятия для представления мешка объектов. В порядке увеличения функций, они являются:

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

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

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

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

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

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

The 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

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

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

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

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

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

выше всего рекомендации.

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

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

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

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

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

сделать, например

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

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

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

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

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

Хансельман Говорит: "Collection<T> выглядит как список, и он даже имеет List<T> внутренне. Каждый метод делегирует внутренний List<T>. Она включает в себя защищенное свойство, которое предоставляет List<T>."

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

редактировать 2: Collection<T> теперь в системе.Коллекции.Пространства имен в объектную модель .Нетто 3.5. В файле справки говорится следующее:

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

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

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

согласно MSDN, список (из T).Add - это" операция O(n) "(при превышении" емкости") во время сбора(T).Добавить - это всегда"операция O(1)". Это было бы понятно, если список реализуется с использованием массива и коллекции связанного списка. Однако, если бы это было так, можно было бы ожидать сбора(T).Пункт должен быть "операция O(n)". Но ... это...не!?! Коллекция (Из Т).Пункт " операция O(1)" так же, как список(из T).Пункт.

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

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

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

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

* = 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()                        *