From Normal Collections to Generic Collections

Prior to .NET Version 2.0 if you wanted to hold a collection of string, integers, or objects you had to work with some of the classes in the System.Collections namespace.

This namespace contains classes and interfaces needed to define collections of objects. Some of the classes are listed in Table 1.

Class Description
ArrayList An ArrayList is similar to an array, but the ArrayList class allows you to add items without managing the size of the list yourself (much like a VB Collection object).
CollectionBase This class is the base for a strongly-typed collection, critical for creating collection classes, described below.
DictionaryBase This class is the base for a strongly-typed collection utilizing associated keys and values. This is similar to the Dictionary object found in VBScript and used by many ASP developers.
SortedList This class represents a collection of keys and values, and is automatically sorted by the key. You can still access the values with either the key or the index number.

Table 1. System.Collections classes

Assume you create a class called Customer. The Customer class has a number of properties, methods, and events. You then want to create several Customer objects within one structure so you can iterate through the collection, performing some operation on each object. You could just create a variable of type Array, ArrayList, or SortedList, but these standard collections can hold any type of object. In other words, you could add a Customer object as the first item in the collection, but you could then add an Employee object as the second item, a string as the third, and so on. If you try to iterate over this collection and apply the Update method, it might work on the Customer and Employee objects, but when your loop attempts to call the Update method of a String object, it will certainly fail.
To get around this sticky situation, you can create your own class that looks like a generic collection object, but restricts its members to only one data type. This new class will include the standard methods of the collection base type, such as the Add and Remove methods, as well as an Item property, but your class’ Add method will only allow you to add Customer objects.

The .NET Framework 2.0 introduced a new namespace called System.Collections.Generics which provides a series of classes that closely resemble the classes in System.Collections. However, these new classes automatically provide the ability to contain only one type of object.

System.Collections Example

Assume that you need to create a Customer object. The structure of the Customer object is very simple, containing just a CompanyName property. Imagine that you want to create a collection class named Customers (note the “s” on the end) to hold a set of Customer objects. You first need to create the Customer class as follows:

public class Customer
{
  public string CustomerName;
}

Next you create your new Customers collection class. Your class must inherit from the System.Collections.CollectionBase class. This base class gives you all of the functionality of a normal collection, but allows you to override any of the base methods, such as Add and Item. The following code provides the new class, and its overridden Add and Item members:

public class Customers : System.Collections.CollectionBase
{
 public void Add(Customer cust)
 {
  base.List.Add(cust);
 }

 public void Remove(int Index)
 {
  if(Index > Count - 1 || Index < 0) {
   // Return error message
  }
  else
   base.List.RemoveAt(Index);
 }

 // This is the "Item" indexer
 public Customer this[ int index ] 
 {
  get
  {
   if (index > Count - 1 || index < 0) {
    // Did not find Customer
    return null;
   }
   else
    return (Customer) base.List[index];
  }
 }
}

In your collection class, you’ll need to override the Add method so that instead of accepting a generic Object type, your method accepts only a Customer object. You can then use the internal List property from the base class to add the customer object to the internal collection of generic objects.

You also need to override the Item method so it returns a Customer object instead of a generic Object data type. This function converts the data in the built-in List property from a generic Object data type to a Customer data type. In C# you need to use the indexer syntax to return an item from this collection. This is done using the syntax shown below:

// This is the "Item" indexer
public Customer this[ int index ] 
{
 get
 {
  if (index > Count - 1 || index < 0)
  {
   // Did not find Customer
   return null;
  }
  else
   return (Customer) base.List[index];
 }
}

Using inheritance, you end up writing a lot less code to implement a collection class when compared to the code you had to write in older language that did not have inheritance. To use this class, you could write code like the following:

private void CustCollection()
{
 Customer cust;
 Customers custColl = new Customers();
 StringBuilder sb = new StringBuilder();

 cust = new Customer();
 cust.CustomerName = "Microsoft Corporation";
 custColl.Add(cust);

 cust = new Customer();
 cust.CustomerName = "PDSA, Inc.";
 custColl.Add(cust);

 sb.Append("Count = " + custColl.Count.ToString());
 sb.Append(Environment.NewLine);

 foreach(Customer c in custColl)
  sb.Append(c.CustomerName + Environment.NewLine);

 lblMsg.Content = sb.ToString();

 custColl.RemoveAt(0);

 lblMsg.Content += "After the removal = " + custColl.Count;
}

The above code creates two new Customer objects, sets the CustomerName property of each to a unique name and then adds each one to the Customers collection class. You can use the Count property from the base class to determine the number of items in the collection, even though you did not implement it in your Customers class. You can use the For Each iterator to loop through each customer object. You can also utilize the base class’ RemoveAt method to remove a specific item at a specified index in the collection.

System.Generics.List Example

Let's now take the same sample shown previously and see how this would work with Generics. The code is considerably simplified since the Generics List class handles all the normal add and remove operations. In addition, using the List<Customer> forces type-safety onto the collection. This means nothing but an object of the type Customers is allowed into this Generic List collection.

public class Customers2 : List<Customer>
{
}

You can now write the exact same code to manipulate this Customers2 class in the exact same way you use the Customers class.

private void CustomerCollection()
{
  Customer cust;
  Customers2 custColl = new Customers2();
  StringBuilder sb = new StringBuilder();

  cust = new Customer();
  cust.CustomerName = "Microsoft Corporation";
  custColl.Add(cust);

  cust = new Customer();
  cust.CustomerName = "PDSA, Inc.";
  custColl.Add(cust);

 sb.Append("Count = " + colcust.Count.ToString());
 sb.Append(Environment.NewLine);

 foreach(Customer c in custColl)
  sb.Append(c.CustomerName + Environment.NewLine);

 lblMsg.Text = sb.ToString();

 custColl.RemoveAt(0);

 lblMsg.Text += "After the removal = " + custColl.Count;
}

As you can see the code from a usage perspective is exactly the same, however, the Customers2 class has eliminated all of the code from the Customers class because of the use of the Generics List<T> class.

Summary

There really is no reason to use the CollectionBase class anymore. In fact, you can not use CollectionBase in Silverlight or Windows Phone apps. You may still find reasons to use ArrayList and possibly even SortedList or other non-generic collections, however, 99% of the time you will take advantage of the Generics namespace and classes.

NOTE: You can download this article and many samples like the one shown in this blog entry at my website. http://www.pdsa.com/downloads. Select “Tips and Tricks”, then “Generic Collections” from the drop down list.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
We frequently offer a FREE gift for readers of my blog. Visit http://www.pdsa.com/Event/Blog for your FREE gift!

Past Blog Content

Blog Archive

No Comments