5,662,937 members and growing! (21,263 online)
Email Password   helpLost your password?
Development Lifecycle » Design and Architecture » Design Patterns     Intermediate

Generic Singleton Pattern using Reflection, in C#

By Martin Lapierre

Use a generic class to create all your Singletons.
C#, Windows, .NET 2.0, .NETVisual Studio, VS2005, Dev

Posted: 5 May 2006
Updated: 5 May 2006
Views: 50,116
Bookmarked: 64 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
37 votes for this Article.
Popularity: 6.92 Rating: 4.41 out of 5
2 votes, 5.4%
1
0 votes, 0.0%
2
4 votes, 10.8%
3
5 votes, 13.5%
4
26 votes, 70.3%
5

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.

Background

There's already a very good article, Implementing the Singleton Pattern in C#, that describes 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 was solving the problem of creating a single instance of a class with a non-accessible constructor (something that all Singletons should have).

Singleton<T>

This is the generic Singleton class:

public static class Singleton<T>
  where T : class
{
  static Singleton()
  {
  }
  
  public static readonly T Instance = 
    typeof(T).InvokeMember(typeof(T).Name, 
                           BindingFlags.CreateInstance | 
                           BindingFlags.Instance | 
                           BindingFlags.NonPublic, 
                           null, null, null) as T;
}

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.

Singleton<T> has a static constructor: this is to make sure that the initialization of the Instance field is lazy (that is, the single instance will be created the first time the field is used and not before). Please refer to C# and beforefieldinit for more details about this issue.

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 InvokeMethod calls its constructor and returns the new instance. The BindingFlags tells InvokeMethod to create a new instance (CreateInstance) and to search the constructor in the non-public (NonPublic) instance members (Instance) of the type. Using non-public constructors is what makes its possible for Singleton<T> to, as an example, create an instance of an internal class from another assembly. The search doesn't include public members, as it is a best practice to keep Singleton constructors private (you don't want anybody else to instantiate these classes).

As you can presume, InvokeMember 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.

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:

// 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Martin Lapierre



Occupation: Web Developer
Location: Canada Canada

Other popular Design and Architecture articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 25 (Total in Forum: 25) (Refresh)FirstPrevNext
RantEasier waymemberinet91121:30 26 Aug '08  
GeneralRe: Easier waymemberMartin Lapierre2:56 27 Aug '08  
GeneralNot convincedmemberPIEBALDconsult19:53 14 Jun '08  
GeneralRe: Not convincedmemberMartin Lapierre2:48 15 Jun '08  
GeneralRe: Not convincedmemberPIEBALDconsult8:22 15 Jun '08  
GeneralRe: Not convincedmemberMartin Lapierre12:35 15 Jun '08  
Generalpublic constructor?memberSean Rhone7:53 20 May '08  
GeneralRe: public constructor?memberMartin Lapierre13:47 20 May '08  
QuestionThread SafetymemberJammer11:04 8 May '08  
AnswerRe: Thread SafetymemberMartin Lapierre14:49 8 May '08  
GeneralRe: Thread SafetymemberJammer1:34 9 May '08  
GeneralReflection not requiredmemberilsandor2:52 18 May '07  
GeneralRe: Reflection not requiredmemberMartin Lapierre4:14 18 May '07  
GeneralFxCop and readonly declarationmemberPlunderBunny18:39 27 Jan '07  
GeneralRe: FxCop and readonly declarationmemberMartin Lapierre4:18 28 Jan '07  
GeneralWatch out for controlsmemberChuck77712:57 21 Aug '06  
GeneralRe: Watch out for controlsmemberMartin Lapierre7:12 22 Aug '06  
GeneralRe: Watch out for controlsmemberChuck7777:50 22 Aug '06  
QuestionRe: Watch out for controls [modified]memberpsidata1:19 2 Mar '07  
AnswerRe: Watch out for controlsmemberpianorain31613:03 3 Apr '07  
GeneralSingletonmembermwdiablo14:32 7 May '06  
GeneralRe: SingletonmemberBrian Leach8:46 9 May '06  
GeneralNice articlememberNinjaCross3:13 6 May '06  
GeneralRe: Nice articlememberMartin Lapierre4:44 6 May '06  
GeneralSuperbmemberJosh Smith17:49 5 May '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 5 May 2006
Editor: Smitha Vijayan
Copyright 2006 by Martin Lapierre
Everything else Copyright © CodeProject, 1999-2008
Web17 | Advertise on the Code Project