System.Collections vs. System.Collection.Generic and System.Collections.ObjectModel

Many people ask how the new.NET Framework 2.0 generic collections relate to the non-generic collections we shipped before. So, here you go. The most important types are in bold font.

List<T> is basically a better ArrayList. It is optimized for speed, size, and power. Use it for majority of internal implementations whenever you need to store items in a container. Do not use it in public APIs.

Dictionary<TKey,TValue> is just a strongly typed Hashtable. Some changes were made to the hashing algorithm. The details are described here.

Collection<T> is a much better CollectionBase. Use it to expose read/write collection output from public APIs. It’s in System.Collections.ObjectModel namespace. Why in a separate namespace and why such strange name? See here.

ReadOnlyCollection<T> is a much better ReadOnlyCollectionBase. It’s in System.Collections.ObjectModel namespace.

Queue<T> and Stack<T> are equivalent to Queue and Stack.

SortedList<TKey,TValue> is basically a generic version of SortedList.

SortedDictionary<TKey,TValue> does not have a corresponding non-generic collection. It’s similar to SortedList and SortedList<TKey,TValue>, but it’s implemented as a balanced tree (red-black tree). Insertions are on average much faster, but some lookups are slightly slower and memory consumption is larger.

IEnumerable<T> is just like IEnumerable, but strongly typed. One difference is that IEnumerable<T> extends IDisposable. The reasons are described here.

ICollection<T> seems like ICollection, but it’s actually a very different abstraction. We found that ICollection was not very useful. At the same time, we did not have an abstraction that represented an read/write non-indexed collection. ICollection<T> is such abstraction and you could say that ICollection does not have an exact corresponding peer in the generic world; IEnumerable<T> is the closest.

IList<T> is just strongly typed IList. We removed the notion of IsFixedSize and the reasons are described here.

IDictionary<TKey,TValue> is roughly equivalent to IDictionary.

DictionaryBase does not have a corresponding generic type. Simply implement IDictionary<TKey,TValue> if you need a custom dictionary.

Also, we added KeyedCollection<TKey,TItem>. It’s a new collection which allows items to be indexed by both a key and an index. Use it to expose collections of items that have natural “names” (keys) from public APIs. You need to inherit from the collection to use it.

And finally many people asked for linked-list. LinkedList<T> was added to .NET Framework 2.0.

So here is the summary:

Non-Generic                        Similar Generic Type
ArrayList              List<T>
Hashtable              Dictionary<TKey,TValue>
SortedList             SortedList<TKey,TValue>
Queue                  Queue<T>
Stack                  Stack<T>
IEnumerable            IEnumerable<T>
ICollection            N/A (use IEnumerable<T> anything that extends it)
N/A                    ICollection<T>
IList                  IList<T>
CollectionBase         Collection<T>
ReadOnlyCollectionBase ReadOnlyCollection<T>
DictionaryBase         N/A (just implement IDictionary<TKey,TValue>
N/A                    SortedDictionary<TKey,TValue>
N/A                    KeyedCollection<TKey,TItem>
N/A                    LinkedList<T>

Let me know if you would like me to blog more information about any of these types.

Comments (24)

  1. tzagotta says:

    Thanks for the summary – very informative.

    Why do you recommend to not use List<T> in public APIs?

  2. Sean Chase says:

    So in a public API that you are shipping, you want to use Collection<T> by deriving from it, correct?

    What about if you are not developing an API, but a layered app and you are exposing classes/collections from a Common assembly through a BL layer…is it OK to use List<T> or should you derive from List<T> and always return the derived class? I kinda like being able to return List<T>. Thoughts?

  3. senkwe says:

    Krzysztof, I’m curious to know why you shouldn’t publically expose List<T>.


  4. Krzysztof Cwalina says:

    I just posted the reasons why we don’t recommend List<T> in public APIs. See

    Sean, using List<T> in app shared libraries may be fine as long as you can and are willing to make some breaking changes to the libraries when you discover that you need change the behavior of the collection and the only way to do it is to change it to Collection<T> and override some members. Such changes are often possible in libraries that are not distributed widely.

  5. Philipp says:

    Just one question: Why in god’s name are there no events or virtual protected methods that allow me to get notified if an item was added or removed? That makes things so tedious. It’s a shame 🙁

  6. Krzysztof Cwalina says:

    Philip, I understand your question is about the collections in System.Collections.Generic namespace. The answer is that such virtual methods make would make the collections slower. To enable the exact scenario you are asking about, we added the System.Collections.ObjectModel namespace. Collections in this namespace do have virtual protected methods which you can use to get notified when an item is added or removed.

  7. Krzysztof Cwalina says:

    Somebody added the following comment to this post, but I accidentally deleted it (Sorry!). Here is that the comment said and my reply is below:

    .NET 1.1, didn’t have a linked list class, so I wrote one.  I was happy to see that it would be included in 2.0.  I’m trying not to use it, though, because it doesn’t implement IList.  I can guess at why you made that decision, but … why did you make that decision??  I always program to interfaces.  That way, if I decide to use an array or something else as my data structure, I only have to change the line in which I instantiated my list.  Developers are smart enough to know which data structures to use!

    Is there any way to override .NET’s LinkedList class?  I kept getting compiler errors, so I put my linked list in the System.Collections.Generic namespace.  Now, I get compiler warnings.  In Java, I’d import the class explicitly, but I don’t know what to do in .NET.

    My Reply:

    We did not implement IList<T> on LinkedList because the indexer would be very slow. If you really need the interface, you probably can inherit from LinkedList<T> and implement the interface on the subtype.

  8. Jimmy says:

    Great post — I look this up all the time 🙂

    What do you say that ICollection has no generic equivalent (or, at least, you suggest using IEnumerable<> instead of ICollection<>)?

  9. Krzysztof Cwalina says:

    ICollection is immutable (no members to change the contents of the collection). ICollection<T> is mutable. This is a substantial difference making the interfaces similar only in their name. One the other hand ICollection and IEnumerable<T> differ by very little.

  10. On utilise tous les jours les interfaces IEnumerable, ICollection, IList quand on d&#233;veloppe en .Net,…

  11. On utilise tous les jours les interfaces IEnumerable, ICollection, IList quand on développe en .Net,

  12. Nital Patel says:

    I am using CollectionBae as below. How can I use generics instead?

    public class ItemCollection : CollectionBase


    public ItemCollection.ItemInfo this[ int index ]


    get { return (ItemCollection.ItemInfo)List[ index ]; }

    set { List[ index ] = value; }


  13. Krzysztof Cwalina says:


    You can use Collection<ItemInfo> instead of your subclass of CollectionBase.

  14. Alessandro says:

    hi Krzysztof, nice post. Thanks.



  15. Enrique Tron says:

    Excelent solution!… a friend did some workaround trying to create this class!!…

    Good things about frameworks=a lot of stuff already done!,

    Bad thing=you should know where it is


  16. Speed Test: Generic List vs. ArrayList

  17. AdamL says:

    Why do Generics provide little to no speed-up over non-Generics, and are also at least 2x slower then running the same code (without Generics) in .NET 1.1?

    I’m talking about a program that stores database information in Hashtables. One of these hashes strings to ArrayLists and there are around 10,000 key, value pairs. The other hashtables are similar in size.

  18. Speed Test: Generic List vs. ArrayList

  19. VeryDxZ says:

    (准确的说是.Net的。但我只对C#比较熟,像VB.Net之类的还有自己以前的一些集合类带过来暂不考虑。下面以.Net2.0的BCL为准,至少它们到3.5都没大变化。) Reference…

  20. Maciey says:

    Anybody knows why below is not working???

    BO2 inherits from BO and M1 shall accept this collection as well. Doesnt it?

    public class BO {}

    public class BO2 :BO {}

    public class BOC <BO> : BindingList<BO>  {}

    public class Client {

    public void M1 (BOC <BO> BOCollection) {


    public void M2 () {

    M1( new BOC<BO2>() );



  21. Sandip says:

    MCTS self-paced exam book lists SortedDictionary as non-generic counterpart of Generic SortedDictionary class. This is not true as I searched the objects under Object Browser in VS 2005 and also you mentioned N/A against its non-generic class. So this blog is very informative and helps.

  22. bhavisha keshwala says:

    thanks sir my knowledge got deeper after reading the theory