SIGN UP MEMBER LOGIN:    
ARTICLE

C# Generic Identity Map -- Creating an Object Pool for Multiple Object Types

Posted by Matthew Cochran Articles | Articles C# January 27, 2008
This article demonstrates a technique through which we can have a type-safe pool object that holds references to many different types of objects.
Reader Level:
Download Files:
 

Let's say we need to keep track of objects that have been instantiated in our application.  The "Identity Map" pattern does just this and we can implement it with a simple Dictionary<TKey, TValue>. However, we need a different dictionary for each type of object which can become cumbersome to keep track of.  Let's look at a technique by which we can have all of our pools in one aggregate pool object.

The trick is maintaining type-safety.  At the gooey center of our aggregate pool we won't necessarily be type-safe, but everything on the crunchy exterior that is publicly available to consuming code will be.  Let's say all of our object have a key property which is an Int32.  If this is the case, we can just build a  type-safe wrapper for a Dictionary<Type, Dictionary<Int32, Object>> where the interior Object is of the type of the key of the outer dictionary.

In order to keep things safe, we'll have to make the instance of the nested dictionary pool private.  Then to safely add an item to the pool, we must first check if there is a "inner" dictionary before we execute the add method.

private Dictionary<Type, Dictionary<Int32, Object>> m_pool;

public void AddItem<T>(Int32 pID, T value)
{
    Type myType = typeof(T);

    if (!m_pool.ContainsKey(myType))
    {
        m_pool.Add(myType, new Dictionary<int, object>());
        m_pool[myType].Add(pID, value);
        return;
    }

    if (!m_pool[myType].ContainsKey(pID))
    {
        m_pool[myType].Add(pID, value);
        return;
    }

    m_pool[myType][pID] = value;
}

When we remove an object from the pool, we'll have to again check that the "inner" dictionary exists:

public bool RemoveItem<T>(Int32 pID)
{
    Type myType = typeof(T);

    if (!m_pool.ContainsKey(myType))
        return false;

    if (!m_pool[myType].ContainsKey(pID))
        return false;

    return m_pool[myType].Remove(pID);
}

If these two methods are the only way to add and remove items from the pool then we can be sure of the type of the object in the inner Dictionary<Int32, Object>. This allows us to have one identity map object for all our loaded objects. So we can have on method to retrieve any object in the pool:

        public T GetItem<T>(Int32 pID)
        {
            // will throw KeyNotFoundException if either of the dictionaries
            // does not hold the required key
            return (T) m_pool[myType][pID];
        }

The thing to be careful of is if you have a long inheritance chains in your object model, you could enter an object in the pool under many different "type" keys and not know how to retrieve the objects put into your dictionary.  Being aware of this, you have to be sure to use consistent types with each method call.

Here is how we would use our aggregate pool:

class Program
{
    public static ObjectPool pool = new ObjectPool();

    static void Main(string[] args)
    {
        Animal dog = new Animal() { Name = "Fido", ID = 1 };
        Vegetable carrot = new Vegetable { Color = "Orange", Identifier = 1, IsTasty = true };
        Mineral carbon = new Mineral() { UniqueID = 2, IsPoisonousToAnimal = false };

        pool.AddItem<Animal>(dog.ID, dog);
        pool.AddItem<Vegetable>(carrot.Identifier, carrot);
        pool.AddItem<Mineral>(carbon.UniqueID, carbon);

        Console.WriteLine("Dog is in the pool -- this statement is " + pool.ContainsKey<Animal>(dog.ID));
        Console.ReadLine();
    }
}

Until next time,
Happy coding

Login to add your contents and source code to this article
share this article :
post comment
 

Very good example! thank you!

Henrique Teles
http://www.bhone.com.br
Desenvolvimento de Sistemas Web

Posted by henrique teles Aug 03, 2010

Hi, I don't see that this code implements an "Identity Map" pattern. Maybe some type of cache.

An Identity Map keeps a record of all objects that have been read from the database in a single business transaction.

How this code do that?
I am looking for an
Identity Map implementation in c#. I saw implementation in java using static ThreadLocal. Do you known an implementation for that?
Thanks
Diego

Posted by D Montal Oct 23, 2009

Hi,

     I'm getting a nullReferenceException when tying to access the GetItems function.
     example 
            foreach (Animal a in col.GetItems<Animal>())
            {
                Console.WriteLine(a.ToString());
            }

Posted by Kevin Alexandre Marchand Sep 23, 2009

This example is very clear and it allows a person to understand dictionary generics more clearly.

Posted by Bonolo Dichabe Feb 13, 2009
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor
PREMIUM SPONSORS
  • ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
    The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor