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):
I'm not going to go over generics. If you want details on generics here are a few links:
I also won't go over anonymous delegates in detail. You can find some useful information here:
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:
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>.
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.
LinkedListNode<T>
Represents a node in a LinkedList<T>.
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;
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>:
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. :)