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);
}
}