patterncsharpMinor
Generic wrapper for System.Runtime.Caching.MemoryCache
Viewed 0 times
genericsystemruntimecachingmemorycachewrapperfor
Problem
I have implemented a simple generic wrapper for MemoryCache class. Its interface looks like ConcurrentDictionary class but I tried to keep it simple. I tried to keep operations atomic, hoping not to break the thread-safety. Is there a mistake about thread-safety? I also want to know if I there are some boxing-unboxing issues I have to think about. Any suggestions about API or some other thing is appreciated.
```
public interface IMemoryCacheWrapper
{
string Name { get; }
long CacheMemoryLimitInBytes { get; }
long PhysicalMemoryLimit { get; }
TimeSpan PollingInterval { get; }
CacheItemPolicy CacheItemPolicy { get; set; }
void AddOrUpdate(string key, T value);
bool TryGetValue(string key, out T value);
bool TryRemove(string key, out T value);
void Remove(string key);
bool ContainsKey(string key);
long Count { get; }
void Dispose();
bool IsDisposed { get; }
}
public class MemoryCacheWrapper : IMemoryCacheWrapper
{
private readonly MemoryCache _memoryCache;
private CacheItemPolicy _cacheItemPolicy;
private bool _isDisposed;
public MemoryCacheWrapper(string name, NameValueCollection config = null)
{
_memoryCache = config != null ? new MemoryCache(name, config) : new MemoryCache(name);
_isDisposed = false;
CacheItemPolicy = new CacheItemPolicy { SlidingExpiration = new TimeSpan(1, 0, 0) };
}
public string Name
{
get { return _memoryCache.Name; }
}
public long CacheMemoryLimitInBytes
{
get { return _memoryCache.CacheMemoryLimit; }
}
public long PhysicalMemoryLimit
{
get { return _memoryCache.PhysicalMemoryLimit; }
}
public TimeSpan PollingInterval
{
get { return _memoryCache.PollingInterval; }
}
public CacheItemPolicy CacheItemPolicy
{
get
{
return _cacheItemPolicy;
}
set
{
if (value != null)
{
```
public interface IMemoryCacheWrapper
{
string Name { get; }
long CacheMemoryLimitInBytes { get; }
long PhysicalMemoryLimit { get; }
TimeSpan PollingInterval { get; }
CacheItemPolicy CacheItemPolicy { get; set; }
void AddOrUpdate(string key, T value);
bool TryGetValue(string key, out T value);
bool TryRemove(string key, out T value);
void Remove(string key);
bool ContainsKey(string key);
long Count { get; }
void Dispose();
bool IsDisposed { get; }
}
public class MemoryCacheWrapper : IMemoryCacheWrapper
{
private readonly MemoryCache _memoryCache;
private CacheItemPolicy _cacheItemPolicy;
private bool _isDisposed;
public MemoryCacheWrapper(string name, NameValueCollection config = null)
{
_memoryCache = config != null ? new MemoryCache(name, config) : new MemoryCache(name);
_isDisposed = false;
CacheItemPolicy = new CacheItemPolicy { SlidingExpiration = new TimeSpan(1, 0, 0) };
}
public string Name
{
get { return _memoryCache.Name; }
}
public long CacheMemoryLimitInBytes
{
get { return _memoryCache.CacheMemoryLimit; }
}
public long PhysicalMemoryLimit
{
get { return _memoryCache.PhysicalMemoryLimit; }
}
public TimeSpan PollingInterval
{
get { return _memoryCache.PollingInterval; }
}
public CacheItemPolicy CacheItemPolicy
{
get
{
return _cacheItemPolicy;
}
set
{
if (value != null)
{
Solution
When implementing the Dispose interface it is advisable to use a two stage clean up. So that when you use this not inside a
Technically you can get away with it here; but I find it is useful to always use this pattern. Maintenance/Bug fixing then becomes easier as you do not need to start messing with other stuff just update the Dispose method. Another reason is that MS recommends this.
using clause the garage collection can also work correctly.Technically you can get away with it here; but I find it is useful to always use this pattern. Maintenance/Bug fixing then becomes easier as you do not need to start messing with other stuff just update the Dispose method. Another reason is that MS recommends this.
public ~MemoryCacheWrapper()
{
// Garbage collection has kicked in tidy up your object.
Dispose(false);
}
// Implement IDisposable.
public void Dispose()
{
// Dispose has been called clean up your object and members that
// are disposable.
Dispose(true);
// Now Make sure that you don't call the cleanup again via the Finalizer
// Effectively you are taking over garbage collection so make sure you
// don't do it again
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
// Only do this once.
if(!this._isDisposed)
{
// If called via IDispose interface then clean up sub-objects.
// That implement the IDispose interface.
if(disposing)
{
// Dispose managed resources.
_memoryCache.Dispose();
}
// Now clean-up and objects that don't implement dispose.
// i.e close any file handles
// Currently nothing to do.
}
_isDisposed = true;
}Code Snippets
public ~MemoryCacheWrapper()
{
// Garbage collection has kicked in tidy up your object.
Dispose(false);
}
// Implement IDisposable.
public void Dispose()
{
// Dispose has been called clean up your object and members that
// are disposable.
Dispose(true);
// Now Make sure that you don't call the cleanup again via the Finalizer
// Effectively you are taking over garbage collection so make sure you
// don't do it again
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
// Only do this once.
if(!this._isDisposed)
{
// If called via IDispose interface then clean up sub-objects.
// That implement the IDispose interface.
if(disposing)
{
// Dispose managed resources.
_memoryCache.Dispose();
}
// Now clean-up and objects that don't implement dispose.
// i.e close any file handles
// Currently nothing to do.
}
_isDisposed = true;
}Context
StackExchange Code Review Q#10572, answer score: 8
Revisions (0)
No revisions yet.