Ku ttan
Ku ttan

Reputation: 11

How to implement a thread safe singleton dictionary class for caching?

I am trying to implement a thread safe dictionary singleton class for caching purpose.

namespace SingletomDict
{
public sealed class MySingleton:IDisposable
{
    private static readonly Lazy<MySingleton> coll = new Lazy<MySingleton>(() => new MySingleton());

    private static Dictionary<string, object> mycoll;

    public static MySingleton Instance 
    {
        get
        {
            return coll.Value;
        }
    }

    private MySingleton()
    {
        mycoll = new Dictionary<string, object>();
    }

    private void SetProperty<T>(string name, T value)
    {
        mycoll.Add(name, value);
    }

    private object GetProperty(string name)
    {
        object value = mycoll[name];
        return value;
    }

    public dynamic this[string index]
    {
        get { return GetProperty(index); }
        set { SetProperty(index, value); }
    }
    public void ReSet()
    {
        mycoll = new Dictionary<string, object>();
    }
}

In the main method, I will be invoking the object as

  MySingleton.Instance["LS"] = "AAA";

  MySingleton.Instance["AB"] = "BBB";

  MySingleton.Instance.ReSet();

I did some research to find the correct implementation. But I couldn't find the appropriate example. Thanks

Upvotes: 1

Views: 2264

Answers (1)

Scott Hannen
Scott Hannen

Reputation: 29222

First declare an interface that describes how you want to use this. Perhaps ICache with a get and set method. (I'd steer clear of dynamic.)

public interface ICache
{
    T Get<T>(string key);
    void Set(string key, object value);
}

Then write an implementation. Your implementation doesn't need to specify what the internals are.

public class Cache : ICache
{
    private readonly ConcurrentDictionary<string, object> _cache 
        = new ConcurrentDictionary<string, object>();
    public T Get<T>(string key)
    {
        object cached;
        if(_cache.TryGetValue(key, out cached) && cached is T)
        {
            return(T) cached;
        }
        return default(T);
    }

    public void Set(string key, object value)
    {
        _cache.AddOrUpdate(key, value, (s, o) => value);
    }
}

If you want to make this a singleton, you can make the constructor private and create a static singleton instance. I would lean toward not doing that. It's better for other classes to depend on the ICache interface than on the implementation, and an interface doesn't have static methods.

Depending on the interface means that you can substitute it with different implementations, like one that depends on MemoryCache.

public class InMemoryCache : ICache
{
    private readonly MemoryCache _cache = MemoryCache.Default;

    public T Get<T>(string key)
    {
        var cached = _cache[key];
        return cached is T ? (T) cached : default(T);
    }

    public void Set(string key, object value)
    {
        _cache[key] = value;
    }
}

If you use a dependency injection (IoC) container you can tell it which implementation of ICache to use for a class that needs an instance of it, and you can specify that the same instance should be provided each time. That way you get to use a single instance of your class as if it was a singleton without having to code it as a singleton.

Upvotes: 3

Related Questions