Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to use a singleton with a non-default constructor in C#?

This is a slight variance of this question: Possible to use a singleton with a non-default constructor in C#?

I have a class that takes parameters for it's constructor. I would like to make this singleton such that the parameters are taken upon initialising the singleton and thus would not need to be passed in each time the instance is retrieved.

My solution (which is not elegant) for this is to have a CreateInstance() static method that takes the parameters and constructs the singleton instance. I would then have another static method GetInstance() which would be parameterless to obtain the singleton instance. In code, I would then need to ensure the logic calls CreateInstance before any calls to GetInstance. However, I cannot enforce this at compile time. I can, however, check at runtime by throwing an exception in GetInstance if it is called before CreateInstance.

Is there anyway I can achieve this behaviour with compile time enforcement? Or at the very least, is there a better way of doing the same thing?

like image 972
millie Avatar asked Apr 04 '11 14:04

millie


2 Answers

There is no way to do it at compile time, because that would be like asking the compiler "can you prove that code X is never executed before code Y is executed, in the presence of multiple threads?". It cannot be done.

As for the runtime behavior of your design, I think this is as good as it can ever be.

You can make it slightly better by exposing a Func<SingletonType> property in your singleton class. When someone asks for the singleton instance and the instance has not already been created, your class would call this "factory method" to construct the singleton. If the factory method is null, then you either throw an exception or (if applicable) construct using some default parameters.

What this does is essentially defer the construction of the singleton until it's actually needed for the first time, so it's some improvement. But the underlying principle is the same.

Update:

As LukeH points out, this is pretty much what Lazy<T> does (.NET 4 only). If possible, use that one instead of writing your own.

like image 197
Jon Avatar answered Oct 14 '22 00:10

Jon


In a classic singleton, the real magic happens in static readonly which creates the instance as soon as it is used:

public class MySingleton
{
    private static readonly _instance = new MySingleton();

    private MySingleton() {}

    public static MySingleton Instance
    {
        get
        {
            return _instance;
        }
    }

}

If you have parameters to pass to constructor, you have to implement locking yourself (note the double if sandwitching the lock):

public class MySingletonWithConstructor
{
    private static _instance;
    private static object _lock = new Object();

    private MySingletonWithConstructor(string myArg) 
    {
        // ... do whatever necessary
    }

    public static MySingletonWithConstructor Instance
    {
        get
        {
            if(_instance==null)
            {
                lock(_lock)
                {
                    if(_instance==null) // double if to prevent race condition
                    {
                        _instance = new MySingletonWithConstructor("Something");
                    }
                }
            }
            return _instance;
        }
    }

}
like image 26
Aliostad Avatar answered Oct 14 '22 00:10

Aliostad