Geeks With Blogs

News

View Anthony Trudeau's profile on LinkedIn

Add to Technorati Favorites


Anthony Trudeau

In a current project I had a need for a lightweight caching mechanism.  My needs were driven by a desire to minimize file access.  The file in question would likely not be too long; however, I couldn't guarantee that.  Therefore, a caching framework such as provided by the Enterprise Library was just too much.  This post talks about what I put together.  The following are the only imports necessary.

using System;

using System.Collections.Generic;

 

My requirements are simple enough.  I want to be able to add an object to a cache based on a string name.  I want to be able to retrieve that same object, and I want to be able to determine (without raising an exception) if the cache contains an object.  And I want to be able to clear the cache.  I will clear the cache if I determine that my file has changed -- thus likely invalidating data within the cache.  Of course I want it strongly typed and to support any type of object (for future use)  and finally it needs to be thread safe.  Here's the pseudo-code interface:

void Add(string key, T newObject)
T GetObject(string key)
void Clear()
bool IsCached(string key)

All of these requirements are simple to implement.  But, I decided that I would add support for one more thing -- ICloneable.  The support wouldn't be an interface implementation, but rather supporting the caching of objects that implement the interface.  This can be important, because the objects I deal with are mutable and I don't want external code to corrupt my object state.

Here's the completed class that does everything I need.

 

internal class ObjectCache<T>

{

    private Dictionary<string, T> _cache = new Dictionary<string, T>();

    private object _syncObject = new object();

 

 

    public ObjectCache()

    {

    }

 

    public void Add(string key, T newObject)

    {

        if (string.IsNullOrEmpty(key))

            throw new ArgumentNullException("key");

        if (newObject == null)

            throw new ArgumentNullException("newObject");

 

        /* create a clone copy for the cache if the object implements
         * ICloneable; this provides an
immutable collection of cached objects */

        T cacheObject = (newObject is ICloneable
                        ? (T)((ICloneable)newObject).Clone() : newObject);

 

        lock (_syncObject)

            _cache.Add(key, cacheObject);

    }

 

 

    public T GetObject(string key)

    {

        T cacheObject;

 

        lock (_syncObject)

            cacheObject = _cache[key];

 

        /* return a copy of the cached object to enforce the

         * immutable collection */

        return (cacheObject is ICloneable
               ? (T)((ICloneable)cacheObject).Clone() : cacheObject);

    }

 

 

    public void Clear()

    {

        lock (_syncObject)

           _cache.Clear();

    }

 

 

    public bool IsCached(string key)

    {

        lock (_syncObject)

            return _cache.ContainsKey(key);

    }

}

Posted on Tuesday, February 24, 2009 11:08 AM .NET | Back to top


Comments on this post: Simple Caching

# re: Simple Caching
Requesting Gravatar...
This looks nice, but wanted to pass along a feature that is part of the Enterprise Library that you could use to help reduce some of the code you have:

For Types other than string:
if (newObject == null)
throw new ArgumentNullException("newObject");

can become:
Guard.ArgumentNotNull(newObject , "newObject ");

For string types:
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException("key");

can become:
Guard.ArgumentNotNullOrEmpty(key, "key");

I am using these guard statements with all my constructors and any method that is dependent on an external resource, such as arguments. The Guard class can be found in the name space below:

Microsoft.Practices.ObjectBuilder2;

Only bringing this up because I believe this is a feature that is not well known about the Enterprise Library and I found it when I was doing a deep dive in to see how the unity framework was creating instances of my objects.
Left by Don Pavlik on Feb 24, 2009 1:41 PM

# re: Simple Caching
Requesting Gravatar...
Thank you for the comments. Your tips will be useful for those using the Enterprise Library. One of the key requirements of this class in my implementation was being light weight -- and that includes coupling. I'm not using the Enterprise Library in this project.
Left by Anthony Trudeau on Feb 24, 2009 2:48 PM

Your comment:
 (will show your gravatar)


Copyright © Anthony Trudeau | Powered by: GeeksWithBlogs.net