Extend a Generic List to Provide Dictionary-Like Lookups

By | September 22, 2008

 

Welcome to a quick and dirty example in which I’ll make use of interfaces, inheritance and generics. I was working with some code that did a lot of iterating over collections to find objects with a particular ID. This is an abstracted example of what I did to simplify and centralize that code in a reusable manner.

If you are using Visual Studio 2008, you could achieve the same kind of reuse with an extension method on your generic list. The project I was working on was in .NET 2.0 and Visual Studio 2005.

This method returns a student’s course based on its ID. The student object here is a private class member. The CurrentCourses property is a List<Course> collection.

private Course FindCourseOld(int id)
{
    foreach (var course in _student.CurrentCourses)
    {
        if (course.ID == id)
        {
            return course;
        }
    }

    return null;
}
 

It’s pretty simple, but suppose you had a dozen or more types with an ID property that were all queries like this? It smells like an opportunity to do some refactoring. We need to keep all the functionality of the List<T> generic collection, including sorting, index operations, and enumerating, but we want to provide a dictionary-type of lookup on the ID property. Let’s inherit from List<T> and add a method to perform our lookup.

Before an object can be stored in this new collection, our child of List<T>, that we are going to create, we need to ensure it has an ID property on which we can operate. To that end, I present to you the IHasIdentifier interface. I know it’s not grammatically correct, but I think it gets the point across.

public interface IHasIdentifier
{
    int ID { get; set; }
}

 

The new interface has a single property named ‘ID’, which many of the types you might consider using in our collection may already have. Next up is the IdentityList<T> itself. The implementation I have here is very simple. There is just a single method, GetItemByID, added to the base class, List<T>.

public class IdentityList<T> : List<T> where T : IHasIdentifier
{
    public T GetItemByID(int id)
    {
        foreach (var obj in this)
        {
            if (obj.ID == id)
            {
                return obj;
            }
        }

        return default(T);
    }
}

 

We’re inheriting from List<T> and specifying that T must implement IHasIdentifier. Now, in the GetItemByID method, we can do our iteration to find the object with the given ID and return it. Finally, let’s take a look at the FindCourseNew method which uses our IdentityList<T> collection.

private Course FindCourseNew(int id)
{
    return _student.CurrentCourses.GetItemByID(id);
}

 

The code here is much cleaner, and there could be more opportunity for code reuse with the IdentityList<T>. Many of the dictionary type of methods could be adapted and used within this collection. You can download the sample code here. As always, any and all feedback is welcome!

 

 

4 thoughts on “Extend a Generic List to Provide Dictionary-Like Lookups

  1. Jamie Ide

    I’m sorry, but I think this is poor advice. You should be using the List.Find method to do this, which will give you O(n) lookup performance, the same as iterating. I don’t recall trying this, but you may be able to create a generic FindById delegate to pass to the Find method. If you need faster lookup, you should copy the elements to a Dictionary which will give you 0(1) performance.

  2. Alvin Ashcraft Post author

    Thanks for the feedback Jamie. I think you are correct about creating a FindByID delegate for use with the Find method.

  3. Jean-Philippe Leconte

    Linq has an extension method to do exactly this.

    From a List :
    list.ToLookup ( k => k.ID );

    From a List :
    list.ToLookup ( k => ( (IHasIdentifier) k).ID );

  4. Pingback: Weekly Link Post 61 « Rhonda Tipton’s WebLog

Comments are closed.