Mar 6, 2008

Hidden Gem: Singleton Factory in C#

Today while browsing through new projects in codeplex I found this gem.  I haven't seen it before and so felt that I should blog about it.

Almost all of us would be aware of the singleton pattern and where it comes handy.  While I love it and use it wherever applicable, there is also a bit of uneasiness when I had to implement the double locking syntax for each singleton class... I wondered whether something can be done to simplify this but I got nowhere.

Now, I've found a solution for this problem in this project.  I'm giving below a simplified version of the Singleton factory found in the project, with example...

namespace Test
{
// this is the class for which I want to maintain a single instance
public class MyClass
{
private MyClass()
{
// private constructor ensures that callers cannot instantiate an object using new()
}
}

// Singleton factory implementation
public static class Singleton<T> where T : class
{
// static constructor, runtime ensures thread safety
static Singleton()
{
// create the single instance of the type T using reflection
Instance = (T)Activator.CreateInstance(typeof(T), true);
}

// serve the single instance to callers
public static T Instance { private set; get; }
}

class Program
{
public static void Main()
{
// test
Console.WriteLine(Object.ReferenceEquals(Singleton<MyClass>.Instance, Singleton<MyClass>.Instance));
}
}
}



The code is self explanatory.  Now, whenever I want a singleton instance of a class, all I have to do is Singleton<ClassTypeName>.Instance and the magic happens.  Isn't this a beauty?  Full credit to Tan Chun Mun.




kick it on DotNetKicks.com

15 comments:

Jelle Hissink said...

You should try to implement ISerializable interface also to ensure serializing / deserializing also uses the singleton...

anastasiosyal said...

That looks pretty cool. Just a small recommendation. Instead of using Activator.CreateInstance I would put a generic restrictor (where T = new()) and simply do new T(). Both the method in your sample and here assume that the singleton class will have a paramerless constructor so a (where T = new()) is a good idea for catching potential errors at compile time.

Cheers,
Anastasiosyal


Anastasiosyal

Chris O. said...

What about Instance = default(T) instead of Instance = (T)Activator.CreateInstance(typeof(T), true)?

Anonymous said...

This is simply a generic implementation of this:

http://www.yoda.arachsys.com/csharp/threads/

AABS said...

The solution to adding parameters and providing a simple means to override the construction in arbitrary ways is shown here: http://aabs.wordpress.com/2007/11/21/a-generic-class-factory-for-c-30/

Shiva said...

@anastasiosyal: we can't use new() since the constructor is private. private constructor is a typical requirement of singleton classes.

@Chris O: default(T) will set the instance value as null

Depechie said...

Hey Shiva !
Nice example, but what Chris o. says is possible...

We have current code running in our project

public abstract class SingletonBase<T> where T : new()
{
private static T s_Instance;

static SingletonBase()
{
s_Instance = new T();
}

public static T Instance
{
get
{
return s_Instance;
}
}
}

public class SingletonExample : SingletonBase<SingletonExample>
{
}

Difference here is that your own derived class inherits the Singleton class.

Anonymous said...

Depechie,

but then SingletonExample can not have a private default constructor so how do you guarantee that nobody creates more SingletonExample instances...

Depechie said...

Anonymous and Shiva... I see what you mean and yes Shiva's solution is better that way :)

Kai said...

With Instance = System
.Runtime
.Serialization
.FormatterServices
.GetUninitializedObject(typeof(T))
as T;
you can create an instance with a private constructor. Also it is faster than Activator.CreateInstance.

Shiva said...

@kai: GetUninitializedObject() will not invoke the constructor on the object that we want to use as a singleton. Clearly, this is not what we want!

Kai said...

@shiva: You're right. What a mistake. The name of the method says everything!

Kai said...

Another try:

using System.Reflection;
...
Instance = typeof(T)
.InvokeMember(typeof(T).Name,
BindingFlags.CreateInstance |
BindingFlags.Instance |
BindingFlags.NonPublic|
BindingFlags.Public,
null, null, null) as T;

Shiva said...

@kai: sure that would work

Anonymous said...


using System.Reflection;
...
Instance = typeof(T)
.InvokeMember(typeof(T).Name,
BindingFlags.CreateInstance |
BindingFlags.Instance |
BindingFlags.NonPublic|
BindingFlags.Public,
null, null, null) as T;


This is not working in WinCE or handheld application. but Activator.CreateInstance and new is working in WinCE and handheld application. From my perception, This why the previous author use it.