HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Generic wrapper for System.Runtime.Caching.MemoryCache

Submitted by: @import:stackexchange-codereview··
0
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)
{

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 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.