Abstract
While it is a bit tricky to implement the Singleton pattern in C#, the steps necessary are well known. There has however been debate about a generic solution for this. This paper provides 3 possible solutions for the generic singleton, and makes a brief comparison.
The Generic Singleton Pattern in C#
A Singleton is a class of which only one instance can exist in the application domain. As simple as this sounds, problems concerning thread-safety arise for the implementation in C#. Fortunately, Jon Skeet provided a neat article [1] describing how to pull this off correctly. There are quite a few catches to watch out for, and it would be nice if we wouldn't have to bother about them while creating a Singleton. This is where the idea of the Generic Singleton comes in. Wouldn't it be nice if we could create a class, not worrying about thread safety or private constructors at all. Then, once we decide it's a good idea to create a singleton, we just pass it as a generic parameter to a GenericSingleton class and voila: we have a construction that ensures there can be only one instance of our class! Many solutions have been proposed in books and on blogs and posts. They all basically boil down to this example, taken from Bishop's book on Design Patterns [2]:
public class Singleton<T> where T : class, new()
{
Singleton() { }
class SingletonCreator
{
static SingletonCreator() { }
// Private object instantiated with private constructor
internal static readonly T instance = new T();
}
public static T UniqueInstance
{
get { return SingletonCreator.instance; }
}
}
While this code provides thread-safety and enforces that only one instance of class T can be created through the Singleton class, it has a major drawback. The generic constraint 'new()' on the type parameter means that the class T will have to provide a public parameterless constructor. This means that any client code will be able to create as many instances of class T as it likes. Thus, this breaks the Singleton pattern. It only works if client code is willing to only access class T via the Singleton class. But there is nothing that forces client code to only use it the way it was intended. While it is in general not necessary for an implementation of a design pattern to robustly exclude all misuse, it should do so as much as possible. The least thing an implementation of a design pattern should do, is encourage the intended use while discouraging misuse.
The solution with the delegate-constructor handshake
So, for the above Generic Singleton implementation to really work, we need to make sure that the public parameterless constructor cannot be called from any other class than the above Generic Singleton.
Easiest way to do this:
public class ReadyForGenericSingleton
{
public ReadyForGenericSingleton(Singleton<ReadyForGenericSingleton> caller)
{
if (caller == null)
{
throw new Exception();
}
}
}
Alternatively, we could use the System.Reflection and/or System.Diagnostics namespaces to collect information about the caller. This is more transparant. But it does have 3 complications. First of all, we inject the caller object into the constructor, and thus no longer fulfill the 'new()' generic constraint: we will have to change this. Second, we will have to have an calling instance, which is not the case in Bishop's solution. We need to change the code to create an instance of the Singleton class. And third, we have an ugly exception. We need to stop the constructor from creating a new object. In an instance constructor, we do not have many options to accomplish this. It is better here to use a 'static factory method' in Joshua Bloch's sense of the term [3]. Consider the following solution:
public sealed class ReadyForGenericSingleton
{
public static ReadyForGenericSingleton CreateInstance(GenericSingleton<ReadyForGenericSingleton>
caller)
{
if (caller != null)
{
return new ReadyForGenericSingleton();
}
else
{
return null;
}
}
private ReadyForGenericSingleton() { }
}
public class GenericSingleton<T> where T : class
{
private static T _instance = null;
static readonly object padlock = new object();
public delegate T CreateInstance(GenericSingleton<T> caller);
private static CreateInstance _createInstance;
public GenericSingleton(CreateInstance createInstance)
{
if (createInstance == null) throw new ArgumentNullException();
_createInstance = createInstance;
}
public T UniqueInstance
{
get
{
lock (padlock)
{
if (_instance == null)
{
_instance = _createInstance(this);
}
return _instance;
}
}
}
}
Use (fragment of NUnit test):
ReadyForGenericSingleton rs1 = new GenericSingleton<ReadyForGenericSingleton>(ReadyForGenericSingleton.CreateInstance).UniqueInstance;
ReadyForGenericSingleton rs2 = new GenericSingleton<ReadyForGenericSingleton>(ReadyForGenericSingleton.CreateInstance).UniqueInstance;
Assert.IsTrue(rs1.equals(rs2));
Here, we created a GenericSingleton class that can have many instances. It is based on the simplest thread-safe example Jon Skeet provides: thread-safety through a lock-object. There are two things to note however: it does enforce a maximum of 1 instance of the class T that is taken as a generic type parameter, and it must be provided with a pointer to a method that creates an instance of type T based on an instance of the GenericSingleton class. If the instance is null, no new object is created and null is returned: no ugly exception necessary; this is the advantage of using a static factory method over a constructor. The static factory method can only create a new instance of the class if it is provided with the instance of the GenericSingleton class; the GenericSingleton class can only be constructed if it is given the pointer to the static factory method through the CreateInstance delegate. This is what we call the 'delegate-constructor handshake'.
So, in this solution, what do we need to do if we want to turn a class into a singleton making use of the GenericSingleton class we presented above?
- Create a static factory method that takes the GenericSingleton as a parameter and checks it isn't null.
- Make sure there are no other properties, constructors or methods that allow client code to create instances of this class.
- Make the class sealed to deny client code to inherit from this class and hide the static factory method through the 'new' keyword, thus disturbing the 'delegate-constructor handshake'.
The solution with the Generic Singleton as an abstract class
The key problem of a generic singleton solution, is that we need a way to construct an instance of a class from the code of the generic singleton class, but we don't want to allow other code to be able to create new instances of the class. We solved this problem in the paragraph above with the 'delegate-constructor handshake'. But there is another solution: we can use the 'protected' keyword that allows access from inheriting classes, but no other classes. Thus, if we create a generic singleton class that is abstract, make our class inherit from it and provide it with a way to create a new instance using 'protected' access, we are nearly there. Last step would be to once again make our class 'sealed' to make sure no class can inherit it and abuse the 'protected' access to create multiple instances. This yields a solution like this:
public abstract class AbstractGenericSingleton<T> where T : AbstractGenericSingleton<T>
{
private static T _instance;
Vithal WadjePosted Oct 20, 2014, 1:50 PM
Jeroen van den Heuvelthanks sir thanks for sharing keep it up
KubaPosted Mar 6, 2009, 8:56 AM
(To be sure I did not make any mistake in my reasoning I assume Instance call should be "ReadyForGenericSingleton.Instance;" instead of ".UniqueInstance", right ?) I would like to know if I am right here... When we have parallel ReadyForGenericSingleton.Instance call from multiple threads there may be an occurrence where they pass through if clause in that block of code: ... get { if (!Initialised) Init(new ReadyForGenericSingleton()); return UniqueInstance; } ... and there is multiple Init call which cause new "ReadyForGenericSingleton" objects creation(what we wanted to avoid in that solution), is that right ?? Of course at the end we get always only one UniqueInstance. Would appreciate for reply and explanation if I am wrong.