Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Singleton pattern with triggerable initialization

I need a singleton that:

  • is lazy loaded
  • is thread safe
  • loads some values at construction
  • those values can be queried at any time
  • the initialization MAY happen at some precise time, before the querying begins - so I must be able to trigger it from the outside somehow. Of course, triggering multiple times should only do the initialization once.

I use .NET 3.5.

I've started with Jon Skeet's implementation (5th version) using a static subclass:

public sealed class Singleton
{
    IEnumerable<string> Values {get; private set;}
    private Singleton()
    {
        Values = new[]{"quick", "brown", "fox"};
    }

    public static Singleton Instance { get { return Nested.instance; } }

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
} 

This ticks almost all the boxes, except the "trigger initialization from outside". Since the actual initialization happens inside the ctor, it can't happen more than once.

How can this be accomplished?

The singleton will be used like this:

public static void Main(){

    //do stuff, singleton should not yet be initialized.

    //the time comes to initialize the singleton, e.g. a database connection is available
    //this may be called 0 or more times, possibly on different threads

    Singleton.Initialize();
    Singleton.Initialize();
    Singleton.Initialize();

    //actual call to get retrieved values, should work
    var retrieveVals = Singleton.Instance.Values;

}
like image 458
Cristian Diaconescu Avatar asked Aug 04 '11 14:08

Cristian Diaconescu


2 Answers

Seems like you could do:

public sealed class Singleton
{
    IEnumerable<string> Values {get; private set;}
    private Singleton(bool loadDefaults)
    {
        if (loadDefaults)
            Values = new[]{"quick", "brown", "fox"};
        else
            Values = new[]{"another", "set", "of", "values"};
    }

    public static Singleton Instance { get { return Nested.instance; } }

    public static void Initialize() {
        Nested.Initialize();
    }

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton(true);
        private static object instanceLock = new object();
        private static bool isInitialized = false; 

        public static void Initialize() {
            lock(instanceLock) {
                if (!isInitialized) {
                    isInitialized = true;
                    instance = new Singleton(false);
                }
            }
        }

    }
} 

Or to create a single instance that will be updated:

public sealed class Singleton
{
    IEnumerable<string> Values {get; private set;}
    private Singleton()
    {
        Values = new[]{"quick", "brown", "fox"};
    }

    public static Singleton Instance { get { return Nested.instance; } }

    private static object instanceLock = new object();
    private static bool isInitialized = false; 

    public static void Initialize() {
        lock(instanceLock) {
            if (!isInitialized) {
                isInitialized = true;
                Instance.Values = new[]{"another", "set", "of", "values"};
            }
        }
    }

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
} 

And the third variation based on your immutable comment and removal of Nested class comment:

public sealed class Singleton
{
    IEnumerable<string> Values {get; private set;}
    private Singleton()
    {
        Values = new[]{"quick", "brown", "fox"};
    }

    private static Singleton instance;
    private static object instanceLock = new object();

    public static Singleton Instance {
        get {
            Initialize();
            return instance;
        }
     }

    public static void Initialize() {
        if (instance == null) {
            lock(instanceLock) {
                if (instance == null)
                    instance = new Singleton();
            }
        }
    }
} 
like image 185
CodeNaked Avatar answered Sep 29 '22 13:09

CodeNaked


The first idea I had was to just use a throwaway variable assigned to the singleton's instance, which would (probably?) trigger the initialization

static Main() 
{
    var unused = Singleton.Instance;
    //this should initialize the singleton, unless the compiler optimizes it out.
    //I wonder if the compiler is smart enough to see this call has side effects.

    var vals = Singleton.Instance.Values;
}

... but programming by side-effects is something I try hard to avoid, so let's make the intention a bit clearer.

public class Singleton {
    public static void Initialize() {
        //this accesses the static field of the inner class which triggers the private Singleton() ctor.  
        Instance._Initialize();
    }
    private void _Initialize()
    { //do nothing
    }

    [the rest as before]
}

so the usage would be:

static Main() 
{
    //still wondering if the compiler might optimize this call out
    Singleton.Initialize();

    var vals = Singleton.Instance.Values;
}

Btw this would also work:

static Main() 
{
    var vals = Singleton.Instance.Values;
}

Compiler optimization aside, I think this deals with all the requirements.

like image 43
Cristian Diaconescu Avatar answered Sep 29 '22 11:09

Cristian Diaconescu