Application Development: Building collections in .NET

In the .NET Framework, collections can be a very powerful tool in object oriented application development. With collections, developers can add object functionality such as add, sorting, and batch processing.

By Phill Miller

If properly used, collections in .NET can be one of the most powerful tools in software development; however, they are often misunderstood and definitely underused. Nearly every software project has the need for a collection of something; for instance, data items, purchase orders, shipping items, tables, and users. Collections allow other developers to use objects easily by providing add, delete, and edit functionality with the same syntax for any type object. In addition, collections can provide rich functionality to developers by providing methods such as sorting, searching, and batch processing for database updates.

Building your collection
Even using the simple collections provided in the .NET Framework, you can see added value; however, the true power of collections comes when you begin creating your own, which use your objects, operating specifically with your classes and types. First, and most importantly, developing your own collections allows users to get back specifically typed objects. This allows the compiler to more readily identify problems in your code and allows Intellisense to work properly.

In addition, creating new collections allows you to provide extra functionality that is specialized to your collection. Some methods may make the most sense when implemented at the collection level. For instance, returning the net security may be best implemented on a collection of authorization records. By implementing your own collections, you can maintain an object oriented structure where the classes do everything you expect—and nothing more.

Choosing your collection type
After you decide to implement your own collection, the next question that you have to ask yourself is what type of collection is needed. Do you need your objects to be sorted? Do you need to be able to access your objects by index or by a unique key? Is there a built-in class in the .NET Framework that you can subclass to get the most out of your functionality?

Table A lists several different kinds of basic lists available in .NET and their features.
Table A
Collection Type Functionality
CollectionBase Simple add and remove functionality
HashTable, DictionaryBase Name value pairs
Stack Last-in, First-out
Queue First-in, Last-out
SortedList Data is sorted as objects are added
DataSet, DataTable Easy data persistence
Collections Types

Enumerating collections
With the advent of C#, all of the C or C++ programmers got a gift from the VB world: the foreach loop, which allows a developer to loop through a collection of objects without having to maintain an index. In many cases, it is necessary to loop through all of the items, but it may not be necessary to know where you are within the list at any given time.

The ability to enumerate through a collection is implemented in many places throughout C# and the .NET Framework. In addition to being able to use the foreach keyword, it is also possible to bind a collection that supports the appropriate interfaces to any kind of multirow control that supports data binding.

The IEnumerable and IEnumerator Interfaces
All that is necessary to be able to data bind your collections is to implement the IEnumerable interface, which allows the runtime to loop through your collection and return back the objects in the order that they exist inside the collection. This is accomplished by the creation of an Enumerator. Let’s take a look at the interface, and that will give you an idea of what is happening as a collection enumerates through itself.

The IEnumerable interface forces a developer to implement one method:
IEnumerator GetEnumerator();

This function returns a type, or more accurately, an interface, of IEnumerator, which is another interface that you must implement inside your class. The IEnumerator class forces you to implement two methods and one property:
bool MoveNext();
void Reset();
object Current {get;}

The following code will give us an insight of how these functions operate when we enumerate through a collection:
foreach(DateTime myDate in myArrayList)

When the runtime reaches the foreach line of code, it calls myArrayList.GetEnumerator(). This GetEnumerator function takes a snapshot of the collection as it exists when the code is executed, and it creates an enumerator based on that snapshot.

Next, the foreach loop tries the MoveNext() function of the Enumerator and uses the Current[] property to get the current object in the collection. This continues until MoveNext() returns false—when there are no more items.

While enumerating through collections is a powerful tool, it is important to remember that you should not edit your collection while enumerating through it. The Enumerator, you will recall, takes a snapshot of the collection when it is created, and then it iterates through that snapshot collection. If you were to add to the collection during the enumeration process, the snapshot of the collection would be invalid, as it would have fewer items than the current collection instance.

Straight to the code
Let’s look at some sample code for building collections. The first collection, MyCollection, shows a simple name value collection with a strongly typed indexer and a strongly typed Add method, returning and accepting types of MyObject (Listing A).

Creating your own collection does not require extensive programming, and the cost/value proportion is very high. Simply subclassing one of the existing collections can be very powerful. In this case, MyCollection does not even directly implement IEnumerable because IEnumerable is already implemented in the NameObjectBaseCollection.

The second class, MyEnumerable, accepts and returns types of MyObject; however, it also implements the IEnumerable interface, this time explicitly (Listing B).

Let’s look at how this works. MyEnumerable also has a class called MyEnumerator, which implements the IEnumerator interface. First, let’s look at the constructor:
public MyEnumerator(MyEnumerable snapshot)
              internalCollection = snapshot;

This constructor takes the snapshot of the collection and assigns it to its internal collection.
public bool MoveNext()
              return idx < internalCollection.Count;

Next, the MoveNext function tests to see whether the collection has any items left, ending the enumeration if there are no more items. Finally, the Current property is determined:
public object Current
                     return internalCollection[idx];

This property is used by the Enumeration to get the current item. Notice that this is a read-only property, as an enumeration should never be assigned.

Expanding collections
You can make your classes more powerful by expanding them and adding functionality as needed. Allowing a collection to be sorted on different fields can provide very useful extended functionality. Integrating search capabilities into your collection allows you to control the search mechanism and optimize the performance of the search. If your collection needs to be persisted to the database, it might be possible to allow for batch updates through your collection, improving your database performance.

Collections power
With all the tools at your disposal in the .NET Framework, it is easy to overlook collections as a way to ease coding and maintain strong object orientation. However, if you begin creating collections, you will see how powerful they can be.

Editor's Picks