kmote
kmote

Reputation: 16735

How to initialize and/or inject a singleton or static dictionary

I need a Dictionary that will be configured at startup and never change. Requirements:

Is there any way to meet all these objectives?

OPTIONS I'VE CONSIDERED:

  1. Private static dictionary. This is simple and easy, it ensures single instance, and keeps it hidden. But I don't know of a way to mock it. Also, don't know how to instantiate it from a config file.
  2. Singleton inheriting from dictionary. Ensures singular instantiation, which can be done from a file in the constructor. I can hide by nesting it in client class. It adds several lines of code, but that's bearable. But I still can't figure out how to inject a mock for testing.

Here's a simplified version of the code demonstrating both methods:

    public class Foo
    {
        private NestedSingleton nestedSingleton = NestedSingleton.GetInstance;
        public string SomeItemFromStatic { get { return (staticDict[1]);  } }
        public string SomeItemFromSingleton { get { return (nestedSingleton[1]);  } }

        private static Dictionary<int, double> staticDict = new Dictionary<int, double>()
        { //Need to instantiate values from config file. But don't know how...
                { 1, 1.345396 },
                { 2, 29.34396 },
                { 3, 17.34396 },
        };      

        class NestedSingleton : Dictionary<int, double>
        {
            private static readonly NestedSingleton _instance;
            static NestedSingleton() 
            {           
                _instance = new NestedSingleton() //Actual code reads from config file here
                {
                    { 1, 1.345396 },
                    { 2, 29.34396 },
                    { 3, 17.34396 },
                };
            }
            private NestedSingleton() { } // Private ctor enforces Singleton pattern
            public static NestedSingleton GetInstance { get { return _instance; } }
        }
    }

Is there some way to meet all stated requirements? (Note: I have not introduced a DI framework at this point. I prefer answers that don't rely on one, if possible.)

Upvotes: 0

Views: 2195

Answers (1)

Fabio
Fabio

Reputation: 32445

Instead of creating dictionary, create dictionary "loader" abstraction, pass instance of this abstraction/interface to the class under test.

You can mock up loader which will return any "faked" dictionary.

Then implement loader as "CachedLoader" which will save loaded dictionary locally and return it instance for consumers through property or method.

Implementation of loader can remain singleton

public interface IConfiguration
{
    public IDictionary<int, int> Data { get; }
}

public class YourClass
{
    private readonly IConfiguration _configuration;

    public YourClass(IConfiguration configuration)
    {
        _configuration = configuration
    }

    public bool GetValue(int id)
    {
        return _configuration.Data[id];
    }
}

public class CachedConfiguartion : IConfiguartion
{
    public IDictionary<int, int> _cachedData;
    public IDictionary<int, int> Data { get { return _cachedCData; } }

    public CachedConfiguartion() {}
}

For CachedConfiguartion you can load dictionary in dedicated method, or make Data of type Lazy<Dictionary<int, int>> and load it on first usage

Upvotes: 1

Related Questions