Craig Gibbons' Lifeblog lifeblog://tri.eat.net

7Jan/050

C# .NET strongly typed custom collection

A while ago I stumbled upon a nifty piece of code which was the exact solution I was looking for. At the time, I had been using ArrayLists to store object collections and casting the ArrayList objects as and when required. I was sure there was a better way and did some googling where I found an article (can't recall where) about deriving from the CollectionBase abstract class to create a strongly typed custom collection. As the VS.NET documentation puts it:

"Provides the abstract (MustInherit in Visual Basic) base class for a strongly typed collection."

Actually implementing this is dead easy but a bit tedious because you have to make a new class for each and every custom collection you want, a problem which is soon to disappear with the arrival of C# v2.0 and generics! The following sample code shows how to implement a strongly typed custom collection using C# and .NET v1.1. I usually create a folder called "Collections" in my Object Relational Mapping (ORM) layer and stick the class in there.

using System;
using System.Collections;

namespace My.Project.ORM.Collections {
 public class ProductCollection : CollectionBase {
  public ProductCollection() {
  }

  public int Add(Product item) {
   return List.Add(item);
  }

  public void Insert(int index, Product item) {
   List.Insert(index, item);
  }

  public void Remove(Product item) {
   List.Remove(item);
  }

  public bool Contains(Product item) {
   return List.Contains(item);
  }

  public int IndexOf(Product item) {
   return List.IndexOf(item);
  }

  public void CopyTo(Product[] array, int index) {
   List.CopyTo(array, index);
  }

  public Product this[int index] {
   get {
    return (Product)List[index];
   }
   set {
    List[index] = value;
   }
  }
 }
}

A useful addition to this collection class is a FindByID() method for finding specific items in the collection by passing an item ID, as follows:

public Product FindByID(int ID) {
 foreach(Product item in List) {
  if(item.ID == ID) {
   return item;
  }
 }
 return null;
}

Lately I have been tinkering with reflection and am just beginning to grasp the full power of this excellent framework feature. I came up with a useful application for reflection pertaining to the above routine FingByID() which achieves the same thing, but in a far more generic way and for any property of an object, not just ID. I'll not go into a full explanation here, there are many articles on reflection all over the web if the reader is interested. So then, the following is a generic collection search routine using reflection.

public ProductCollection FindByProperty(string PropertyName, object Value) {
 try {
  ProductCollection foundItems = new ProductCollection();

  foreach(Product item in List) {
   System.Type itemType = item.GetType();
   PropertyInfo[] itemProperties = itemType.GetProperties();

   foreach(PropertyInfo info in itemProperties) {
    if(info.Name == PropertyName) {
     object itemValue = info.GetValue(item, null);
     if(Convert.ChangeType(itemValue, info.PropertyType).Equals(Value)) {
      foundItems.Add(item);
     }
    }
   }
  }

  return foundItems;
 } catch(Exception ex) {
  throw new Exception("The Value passed could not be cast to the specified property's type", ex);
 }
}

The code above would be called as follows:

ProductCollection foundProducts = products.FindByProperty("ID", 1);

.NET rocks!

Filed under: Tech Leave a comment
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.