Click here to Skip to main content
15,867,704 members
Articles / Programming Languages / C#

Generic Singleton Pattern using Reflection, in C#

Rate me:
Please Sign up or sign in to vote.
4.67/5 (46 votes)
9 Jun 2009Ms-PL3 min read 248.9K   1.6K   145   49
Use a generic class to create all your Singletons.

Introduction

This article presents a generic class that uses Reflection to create a single instance of any class. It can be used to instantiate Singletons from public classes with non-public constructors, and Singletons from non-public classes as well.

The main motivation for this solution is to have the Singleton pattern written in only one place, reusable by all classes that need to follow that pattern.

Simply use Singleton<T>.Instance to get a Singleton instance.

Background

There are already very good articles (Lazy vs. Eager Init Singletons / Double-Check Lock Pattern and Implementing the Singleton Pattern in C#) that describe the challenges and caveats of developing a Singleton in .NET; I won't go into the details again. There are also some Singletons using Generics here and there (see Generic Singleton Provider as an example), but none were solving the problem of creating a single instance of a class with a non-accessible constructor (something that all Singletons should have).

Design

Singleton<T> uses the Double-Check Lock Pattern rather than static type initialization. The motivation behind this choice is that error-recovery and retries after a type-initializer failure are impossible in .NET (once a type-initializer fails, trying to create a class instance will always throw an exception, even if the error was meanwhile resolved). The chosen implementation strategy provides more flexibility for better error recovery.

Singleton<T> also forces the target class constructor to be private or protected to prevent casual class instantiation.

Singleton<T>

This is the generic Singleton class:

C#
public static class Singleton<T>
       where T : class
{
  static volatile T _instance;
  static object _lock = new object();

  static Singleton()
  {
  }

  public static T Instance
  {
    get
    {
      if (_instance == null)
        lock (_lock)
        {
          if (_instance == null)
          {
            ConstructorInfo constructor = null;

            try
            {
              // Binding flags exclude public constructors.
              constructor = typeof(T).GetConstructor(BindingFlags.Instance | 
                            BindingFlags.NonPublic, null, new Type[0], null);
            }
            catch (Exception exception)
            {
              throw new SingletonException(exception);
            }

            if (constructor == null || constructor.IsAssembly)
            // Also exclude internal constructors.
              throw new SingletonException(string.Format("A private or " + 
                    "protected constructor is missing for '{0}'.", typeof(T).Name));

            _instance = (T)constructor.Invoke(null);
          }
        }

      return _instance;
    }
  }
}

The type parameter T represents the class that must be instantiated like a Singleton.

Singleton<T> uses the class constraint to force the type parameter to be a reference type. The new() constraint, which forces the type parameter to have a public parameterless constructor, is not used here, because the goal of the generic class is to provide single instance creation for classes with non-public constructors.

_instance is defined using the volatile keyword, and a dummy object, _lock, is used to synchronize threads with the double-check lock pattern. See Lazy vs. Eager Init Singletons / Double-Check Lock Pattern for the details of this strategy.

Singleton<T> has a static constructor: it simply makes sure that static fields initialization occurs when the Instance property is called the first time and not before.

The initialization of the _instance field is made by Reflection using the type parameter. typeof(T) first gets the type of the type parameter, then GetConstructor gets its constructor, and Invoke finally returns the new instance. The BindingFlags tells GetConstructor to search the constructor in the non-public (BindingFlags.NonPublic) instance members (BindingFlags.Instance) of the type. The search doesn't include public members, and the last if statement excludes internal constructors, as it is a best practice to keep Singleton constructors private or protected (you don't want anybody else to instantiate these classes).

As you can presume, GetConstructor can throw an exception if the type parameter is not a class, as the class constraint also allows interface, delegate, or array types. There's just so much you can do with these constraints.

Using Singleton<T>

Another best practice of the Singleton pattern is to have every Singleton return its own single instance. This is usually done by a static property named Instance. The following code snippet shows how to use Singleton<T> in a property.

C#
public static SingleInstanceClass Instance
{
  get
  {
    return Singleton<SingleInstanceClass>.Instance;
  }
}

Demo

The demo shows the life cycle of the SingleInstanceClass singleton. The code is self-explanatory:

C#
// SingleInstanceClass is a Singleton.

public class SingleInstanceClass
{
  // Private constructor to prevent
  // casual instantiation of this class.
  private SingleInstanceClass() 
  {
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("SingleInstanceClass created.");
    Console.ResetColor();

    _count++;
  }
  
  // Gets the single instance of SingleInstanceClass.
  public static SingleInstanceClass Instance 
  { 
    get { return Singleton<SingleInstanceClass>.Instance; } 
  }

  public static int Count { get { return _count; } }
  public static void DoStatic()
      { Console.WriteLine("DoStatic() called."); }
  public void DoInstance()
      { Console.WriteLine("DoInstance() called."); }

  // Instance counter.
  private static int _count = 0;
}

class Program
{
  static void Main()
  {
    // Show that initially the count is 0; calls
    // a static property which doesn't create the Singleton.
    Console.WriteLine("---");
    Console.WriteLine("Initial instance count: {0}", 
                      SingleInstanceClass.Count);

    // Similar to above; show explicitly that calling
    // a static methods doesn't create the Singleton.
    Console.WriteLine("---");
    Console.WriteLine("Calling DoStatic()");
    SingleInstanceClass.DoStatic();
    Console.WriteLine("Instance count after DoStatic(): {0}", 
                      SingleInstanceClass.Count);

    // Show that getting the instance creates the Singleton.
    Console.WriteLine("---");
    Console.WriteLine("Calling DoInstance()");
    SingleInstanceClass.Instance.DoInstance();
    Console.WriteLine("Instance count after first DoInstance(): {0}", 
                      SingleInstanceClass.Count);

    // Show that getting the instance
    // again doesn't re-instantiate the class.
    Console.WriteLine("---");
    Console.WriteLine("Calling DoInstance()");
    SingleInstanceClass.Instance.DoInstance();
    Console.WriteLine("Instance count after second DoInstance(): {0}", 
                      SingleInstanceClass.Count);
    Console.ReadKey();
  }
}

The program output is:

Running the Singleton demo...

Conclusion

There are many ways to implement the Singleton pattern in C#. Singleton<T> uses Reflection to make it a write-once-for-all solution.

History

  • 2009-04-18: Refactored to use the double-check lock pattern and the volatile keyword rather than a type-initializer. Also added SingletonException.
  • 2009-06-07: Replaced typeof(T).InvokeMember with typeof(T).GetConstructor to support the Compact Framework.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Web Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionAlternative way (thread safe) with the same result Pin
Alexey Nikitin14-Dec-13 21:55
Alexey Nikitin14-Dec-13 21:55 
GeneralCheck out my idea. [modified] Pin
Svett28-Jul-09 0:46
Svett28-Jul-09 0:46 
GeneralRe: Check out my idea. Pin
Martin Lapierre28-Jul-09 2:30
Martin Lapierre28-Jul-09 2:30 
GeneralRe: Check out my idea. Pin
Svett28-Jul-09 2:40
Svett28-Jul-09 2:40 
GeneralAlternative for Compact Framework users Pin
Robert.AC.Allen3-Jun-09 3:13
Robert.AC.Allen3-Jun-09 3:13 
GeneralRe: Alternative for Compact Framework users Pin
Martin Lapierre7-Jun-09 6:30
Martin Lapierre7-Jun-09 6:30 
QuestionWhat happens If . . .? Pin
KrazyKZ12-May-09 9:38
KrazyKZ12-May-09 9:38 
AnswerRe: What happens If . . .? Pin
Martin Lapierre12-May-09 13:38
Martin Lapierre12-May-09 13:38 
QuestionWhat happens If . . .? Pin
KrazyKZ12-May-09 9:32
KrazyKZ12-May-09 9:32 
GeneralI find the nested method better and easier to understand Pin
Tawani Anyangwe2-May-09 9:39
Tawani Anyangwe2-May-09 9:39 
http://www.yoda.arachsys.com/csharp/singleton.html[^]
<font color='blue'>public sealed class</font> <font color='teal'>Singleton</font>
{
    <font color='teal'>Singleton</font>()
    {
    }

    <font color='blue'>public static</font> <font color='teal'>Singleton</font> Instance
    {
        <font color='blue'>get</font>
        {
            <font color='blue'>return</font> <font color='teal'>Nested</font>.instance;
        }
    }
    
    <font color='blue'>class</font> <font color='teal'>Nested</font>
    {
        <font color='green'>// Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit</font>
        <font color='blue'>static</font> Nested()
        {
        }

        <font color='blue'>internal static readonly</font> <font color='teal'>Singleton</font> instance = <font color='blue'>new</font> <font color='teal'>Singleton</font>();
    }
}

GeneralRe: I find the nested method better and easier to understand Pin
Martin Lapierre2-May-09 10:02
Martin Lapierre2-May-09 10:02 
GeneralNice approach Pin
darrellp23-Apr-09 1:35
darrellp23-Apr-09 1:35 
QuestionWhy not use a Dependency Injection Container? Pin
Jeff Doolittle20-Apr-09 18:41
Jeff Doolittle20-Apr-09 18:41 
AnswerRe: Why not use a Dependency Injection Container? Pin
Martin Lapierre21-Apr-09 5:05
Martin Lapierre21-Apr-09 5:05 
GeneralRe: Why not use a Dependency Injection Container? Pin
KrazyKZ12-May-09 9:24
KrazyKZ12-May-09 9:24 
AnswerRe: Why not use a Dependency Injection Container? Pin
jim lahey22-Jan-13 6:19
jim lahey22-Jan-13 6:19 
RantEasier way Pin
inet91126-Aug-08 20:30
inet91126-Aug-08 20:30 
GeneralRe: Easier way Pin
Martin Lapierre27-Aug-08 1:56
Martin Lapierre27-Aug-08 1:56 
GeneralNot convinced Pin
PIEBALDconsult14-Jun-08 18:53
mvePIEBALDconsult14-Jun-08 18:53 
GeneralRe: Not convinced Pin
Martin Lapierre15-Jun-08 1:48
Martin Lapierre15-Jun-08 1:48 
GeneralRe: Not convinced Pin
PIEBALDconsult15-Jun-08 7:22
mvePIEBALDconsult15-Jun-08 7:22 
GeneralRe: Not convinced Pin
Martin Lapierre15-Jun-08 11:35
Martin Lapierre15-Jun-08 11:35 
GeneralRe: Not convinced Pin
giammin20-Apr-09 22:27
giammin20-Apr-09 22:27 
AnswerRe: Not convinced [modified] Pin
Martin Lapierre21-Apr-09 4:16
Martin Lapierre21-Apr-09 4:16 
GeneralRe: Not convinced Pin
giammin21-Apr-09 7:15
giammin21-Apr-09 7:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.