I have a generic base class for value caching functionality.
public abstract class CachedValueProviderBase<T> : ICachedValueProvider<T> where T : class
{
private Cache Cache { set; get; }
protected string CacheKey { get; set; }
protected int CacheSpanInMinutes { get; set; }
private static readonly object _cacheLock = new object();
public T Values
{
get
{
T value = Cache[CacheKey] as T;
if (value == null)
{
lock (_cacheLock)
{
value = Cache[CacheKey] as T;
if (value == null)
{
value = InitializeCache();
}
}
}
return value;
}
}
protected CachedValueProviderBase()
{
Cache = HttpRuntime.Cache;
CacheSpanInMinutes = 15;
}
public T CacheValue(T value)
{
if (value != null)
{
lock (_cacheLock)
{
Cache.Insert(CacheKey, value, null, DateTime.UtcNow.AddMinutes(CacheSpanInMinutes),
Cache.NoSlidingExpiration);
}
}
return value;
}
private T InitializeCache()
{
T value = Initialize();
CacheValue(value);
return value;
}
protected abstract T Initialize();
}
I have several classes that make use of this base class and as long as the T is different it is fine. When two sub classes use the same T, string for example, they share the same cache lock object. What is the best way of implementing the logic in a base class but still giving each sub class it’s own cache lock object?
Update
After the suggestions below I have updated my class:
public abstract class CachedValueProviderBase<T> : ICachedValueProvider<T> where T : class
{
private Cache Cache { set; get; }
protected string CacheKey { get; set; }
protected int CacheSpanInMinutes { get; set; }
private object _cacheLock = new object();
public T Values
{
get
{
T value = Cache[CacheKey] as T;
if (value == null)
{
lock (_cacheLock)
{
value = Cache[CacheKey] as T;
if (value == null)
{
value = InitializeCache();
}
}
}
return value;
}
}
protected CachedValueProviderBase()
{
Cache = HttpRuntime.Cache;
CacheSpanInMinutes = 15;
}
public T CacheValue(T value)
{
if (value != null)
{
Cache.Insert(CacheKey, value, null, DateTime.UtcNow.AddMinutes(CacheSpanInMinutes),
Cache.NoSlidingExpiration);
}
return value;
}
private T InitializeCache()
{
T value = Initialize();
CacheValue(value);
return value;
}
protected abstract T Initialize();
}
}
My sub classes are now singletons so I could get rid of the static cachelock object making it an instance variable.
Well, just remove the static modifier on your cacheLock object.
That keyword forces the field to be shared between all instances of subclasses that share the same generic parameter type.
If you remove it, the cacheLock object will be private to each instance of a subclass, regardless of the generic parameter’s type.
Should be :
Hope that helps