Monday, March 10, 2008

Generic Singleton Factory

This is a great way to create a Singleton instance of an exiting class without needing to specifically design it as a singleton:

// Singleton factory implementation
public static class Singleton where T : class
{
static Singleton()
{
// create the single instance of the type T using reflection
Instance = (T)Activator.CreateInstance(typeof(T), true);
}
public static T Instance { private set; get; }
}

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

1 comment:

rsn81 said...

using System;

namespace Rsdn {
public class ReflectionSingleton<T> where T: class {
private static readonly T t;

static ReflectionSingleton() {
t = (T) Activator.CreateInstance(typeof(T), true);
}

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

------------------

namespace Rsdn {
public class Singleton<T> where T: class, new() {
private static T t;

public static T Instance {
get {
if (t == null)
t = new T();
return t;
}
}
}
}

------------------

using System;

using NUnit.Framework;

namespace Rsdn {
[TestFixture]
public class SingletonTest {
/// <summary>
/// It's true. However can't use private constructor, but it's compile time error
/// </summary>
[Test]
public void TestSingleton() {
Assert.AreEqual(Singleton<object>.Instance, Singleton<object>.Instance);
// Assert.AreEqual(Singleton<NonTrivailClass>.Instance, Singleton<NonTrivailClass>.Instance);
// Compiler error:
// The type 'Rsdn.NonTrivailClass' must have a public parameterless constructor
// in order to use it as parameter 'T' in generic class 'Rsdn.Singleton<T>'
}

/// <summary>
/// It's cool, but slow, because it's reflection
/// </summary>
[Test]
public void TestReflectionSingleton() {
Assert.AreEqual(ReflectionSingleton<PrivateClass>.Instance,
ReflectionSingleton<PrivateClass>.Instance);
}

/// <summary>
/// It's compile, but crash in runtime - bug
/// </summary>
[ExpectedException(ExceptionType = typeof(TypeInitializationException))]
public void TestCrachReflectionSingleton() {
Assert.AreEqual(ReflectionSingleton<NonTrivailClass>.Instance,
ReflectionSingleton<NonTrivailClass>.Instance);
}
}

public class NonTrivailClass {
public NonTrivailClass(int i) {
}
}

public class PrivateClass {
private PrivateClass() {
}
}
}