What is the difference between List (of T) and Collection(of T)?

I've seen them used in a lot of the same ways, and I am worried I'm about to go down a path in design that is irreversible if I don't understand this better. Also, I am using .NET.


In C#, there are three concepts for representing a bag of objects. In order of increasing features, they are:

  • Enumerable - unordered, unmodifiable
  • Collection - can add/remove items
  • List - allows items to have an order (accessing and removing by index)

Enumerable has no order. You cannot add or remove items from the set. You cannot even get a count of items in the set. It strictly lets you access each item in the set, one after the other.

Collection is a modifiable set. You can add and remove objects from the set, you can also get the count of items in the set. But there still is no order, and because there is no order: no way to access an item by index, nor is there any way to sort.

List is an ordered set of objects. You can sort the list, access items by index, remove items by index.

In fact, when looking at the interfaces for these, they build on one another:

  • interface IEnumerable<T>

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

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

    • Insert
    • IndexOf
    • RemoveAt

When declaring variables, or method parameters, you should choose to use

  • IEnumerable
  • ICollection
  • IList

based on what conceptually you need to do with the set of objects.

If you just need to be able to do something to every object in a list, then you only need IEnumerable:

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

You don't care if the Users are kept in a List<T>, Collection<T>, Array<T> or anything else. You only need the IEnumerable<T> interface.

If you need to be able to add, remove, or count the items in a set, then use a Collection:

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

If you care about a sort order, and need the order to be correct, then use a List:

IList<User> users = FetchUsers(db);

In chart form:

| 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 index      |                |                | X        |
| Getting index of item  |                |                | X        |

The List<T> and Collection<T> in System.Collections.Generic are two classes that implement these interfaces; but they aren't the only classes:

  • ConcurrentBag<T> is an ordered bag of objects (IEnumerable<T>)
  • LinkedList<T> is a bag where you are not allowed to access items by index (ICollection); but you can arbitrarily add and remove items from the collection
  • SynchronizedCollection<T> is an ordered collection, where you can add/remove items by index

So you can easily change:

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

SaveEveryUser(users);

tl;dr

  • Enumerable - access items, unordered, unmodifiable
  • Collection - can be modified (add,delete,count)
  • List - can access by index

Choose the concept you need, then use the matching class.


Collection<T> is a customizable wrapper around IList<T>. While IList<T> is not sealed, it doesn't provide any customization points. Collection<T>'s methods are by default delegated to the standard IList<T> methods, but can be easily overridden to do what you want. It is also possible to wireup events inside a Collection<T> that I don't believe could be done with an IList.

In short, it's much easier to extend it after the fact, which could potentially mean a lot less refactoring.


List<T> is intended for internal use within the application code. You should avoid writing public APIs that accept or return List<T> (consider using a superclass or a collection interface instead).

Collection<T> serves a base class for custom collections (although it can be used directly).

Consider using Collection<T> in your code unless there are specific features of List<T> that you need.

The above are just recommendations.

[Adapted from: Framework Design Guidelines, Second Edition]


List<T> is a very commonly seen container, because it is so very versatile (with lots of handy methods like Sort, Find, etc) - but has no extension points if you want to override any of the behaviour (check items on insert, for example).

Collection<T> is a wrapper around any IList<T> (defaulting to List<T>) - it has the extension points (virtual methods), but not as many support methods like Find. Because of the indirection, it is slightly slower than List<T>, but not by much.

With LINQ, the extra methods in List<T> become less important, since LINQ-to-Objects tends to provide them anyway... for example First(pred), OrderBy(...), etc.


List is faster.

Do for example

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


}

on my machine List<> is almost twice as fast.

Edit

I can't understand why people are downvoting this. Both on my work machine and my home machine the List<> code is 80% faster.