Generic Collections I
In one of my first posts I briefly mentioned that I would discuss a bit about what I've learned about using the new generic collections. I've been putting it off a bit because I knew it would be a bit lengthy, but I really feel this is important so I'm going to push myself to start making the effort. ;) Here's what I plan to cover (in relation to generic collections):
- Advantages of generic collections
- Predicates & other System delegate types
- Anonymous delegates
- Subclassing generic collections
- Other resources (including Power Collections)
I'm not going to go over generics. If you want details on generics here are a few links:
- An Introduction to C# Generics
- Introducing Generics in the CLR
- More on Generics in the CLR
- Introducing .NET Generics
- Generics (C# Programmer's Reference)
- Generics (C++)
I also won't go over anonymous delegates in detail. You can find some useful information here:
- C# 2.0: Create Elegant Code with Anonymous Methods, Iterators, and Partial Classes
- Anonymous Methods (C# Programmers Reference)
Introduction
Generic collections are the generic equivalents (I like to think of them as replacements) for the System.Collections classes. They are found in the System.Collections.Generic space.
Generic collections have a number of advantages over the old collections. Chief among them are:
- They are type safe.
- Better performance. (no boxing/unboxing!)
- Richer functionality through System defined delegate types.
To top it off they are quite compatible with the old collections and methods that use them. Both ArrayList and List<T> support IList, ICollection, IEnumerable, and ICloneable for example. If existing methods use the old interfaces for parameters there is nothing extra you have to do to start using the generic collections. (Hey, look! A great reason to take the interface (IList) as a parameter instead of the collection class (ArrayList).) Converting is easy beyond this as the old collections take ICollection or IDictionary as a constructor parameter.
Here's a quick overview of how the new collections map to old ones (from: Generics in the .NET Framework Class Library (C# Programmers Reference))
Generic Class or Interface |
Description |
Corresponding Non-Generic Type |
Collection<T> ICollection<T> |
Provides the base class for a generic collection. |
CollectionBase ICollection |
Comparer<T> IComparer<T> IComparable<T> |
Compares two objects of the same generic type for equivalence and for sorting. |
Comparer IComparer IComparable |
Dictionary<K, V> IDictionary<K,V> |
Represents a collection of key/value pairs that are organized based on the key. |
Hashtable IDictionary |
Dictionary<K, V>.KeyCollection |
Represents the collection of keys in a Dictionary<K, V>. |
None. |
Dictionary<K, V>.ValueCollection |
Represents the collection of values in a Dictionary<K, V>. |
None. |
IEnumerable<T> IEnumerator<T> |
Represents a collection that can be iterated using foreach. |
IEnumerable IEnumerator |
KeyedCollection<T, U> |
Represents a keyed collection. |
KeyedCollection |
LinkedList<T> |
Represents a doubly linked list. |
None. |
LinkedListNode<T> |
Represents a node in a LinkedList<T>. |
None. |
List<T> IList<T> |
Implements the IList<T> interface using an array whose size is dynamically increased as required. |
ArrayList IList |
Queue<T> |
Represents a first-in, first-out collection of objects. |
Queue |
ReadOnlyCollection<T> |
Provides the base class for a generic read-only collection. |
ReadOnlyCollectionBase |
SortedList<K, V> |
Represents a collection of key/value pairs that are sorted by key based on the associated IComparer<T> implementation. |
SortedList |
Stack<T> |
Represents a simple last-in-first-out (LIFO) collection of objects. |
Stack |
First Look at a Generic Collection Class
The best place to start is to look at the workhorse of the generic collection family, the generic List class, or List<T>. List<T> is meant to replace the functionality of ArrayList. It is a simple ordered collection of objects of type <T>. You can think of it as a wrapped array because that's precisely what it is--internally data is stored as private T[] _items;
As with any array, appending is usually fast (unless the array is being resized) and insertion gets proportionally slower as the number of elements grows. I've already mentioned that it supports IList, ICollection, and IEnumerable. It also supports the generic equivalents IList<T>, ICollection<T>, and IEnumerable<T>.
Lets take a look at some simple usage of List<T>, shall we? (Finally, some code!)
// Creating a List<T> (Also has constructors that take a collection or specify the initial size) List<int> myNumbers = new List<int>(); // Adding a value myNumbers.Add(42); // Adding a range of values myNumbers.AddRange(new int[]{1,2,3}); // Inserting a value myNumbers.Insert(myNumbers.Count - 3, 0); // Iterating foreach (int number in myNumbers) { // Output is 42, 0, 1, 2, 3 Console.WriteLine(number.ToString()); }
The code above should be pretty self explanatory. Here is a summary of the functionality that is available to you in List<T>:
- Add or insert objects of collections of type T
- Removal
- Remove, RemoveAt, RemoveRange, RemoveAll
- Sorting
- Sort (Comparison<T> )
- Reverse
- Conversion
- ConvertAll (Converter<T,U> )
- CopyTo(T[])
- Searching (Predicate<T> )
- Exists
- Find, FindAll, FindLast
- FindIndex, FindLastIndex, IndexOf, LastIndexOf
- TrueForAll
- Iterating
- ForEach (Action<T> )
In bold you will see that I've called out the System delegate types. They are the key to unlocking super rich functionality within these classes. This makes a nice transition to my next blog entry where I'll start by taking a look at Predicate<T> and then this discussion will get really interesting. :)
Comments
Anonymous
July 22, 2005
In yesterday's post I went over the very basics of generic collections in the 2.0 .Net framework.&nbsp;...Anonymous
February 12, 2006
Jeremy, could you please also tell some more about Dictionary<K, V>.KeyCollection ? (Oh, of coruse if you still care about such matters ;) ..
Is it intended to index generic collection's keys/values by integer ? 't seems msdn2 doesn't help much ..
thank youAnonymous
March 24, 2006
KeyCollections are passed back by the .Keys property. I use them (and .Values) in a few places to easily iterate through the keys (or values) that are in use. I'll see if I can't write up some examples in the future.Anonymous
May 24, 2007
In C# 2.0, generics and generic collections are notable and very useful features to pay attention to:Anonymous
February 17, 2008
In yesterday's post I went over the very basics of generic collections in the 2.0 .Net framework. Today