Click here to Skip to main content
15,879,239 members
Articles / Programming Languages / C#
Article

Fun with Singletons in C# 2.0

Rate me:
Please Sign up or sign in to vote.
4.68/5 (32 votes)
21 Nov 20068 min read 89.7K   507   84   28
This article will show you how to create generic singletons that honor all of their properties and at the same time are extensible enough to handle not so obvious scenarios.

Introduction

Coming from a hardcore C++ development background, I had amazed myself several times reading such excellent books like Modern C++ Design: Generic Programming and Design Patterns Applied from Andrei Alexandrescu or the source code of Boost. They are extremely hard to understand (it took me several weeks and a big headache to get a glimpse of what they were talking about) but I would recommend them anytime to C# developers who really want to uncover the real potential of C# generics.

With the new generics support given by C# 2.0, some common design patterns can be generalized to work with any type. Exploiting the capabilities given by the type system, reflection, and generics, we can accomplish typesafe modular code customization and automation. Fun with Singletons is just a demonstration of the array of possibilities that C# 2.0 features introduce.

The audience for this article is anyone with a decent knowledge on generics; however, to really appreciate it, an exposure to the C++ templates engine would be desired.

Background

The singleton is by far the most common design pattern in literature, it has been implemented countless times in several languages. In C#, the typical implementation requires us to implement the Instance method and be aware of locking, depending on if we are creating it lazily or statically.

One night (like 8 months ago), I asked to myself: Wouldn't it be nice to inherit from a class and automatically have the singleton implementation done? And what about all security controls required to make sure I am not making a mistake in the implementation of my class?

The response didn't took much time to come: yes, I can do that in C++; however, the aim was to investigate one of those interesting features back then with the Beta 2 of Visual Studio 2005, C# generics. The solution was heavily inspired by Alexandrescu's Generic Singleton Pattern, also known as "Allocator Based Singleton". And, here we go.

Generic Singletons

At the time, I had been looking to code the singletons in a way that they could be used like this:

C#
public class MySingleton : Singleton<MySingleton>
{
}

Luckily, up to that point, C# generics were enough to handle a situation like that one. So after some time, trying to get a grasp of how generics worked in C# 2.0, I came up with the following Singleton class:

C#
public class Singleton<T> where T : new ()
{
   private static T instance;
   public static T Instance { get { return instance; } }
   static Singleton ()
   {
      instance = new T();
   }

   protected Singleton ()
   {
   }
}

public class MySingleton : Singleton<MySingleton>
{
   public MySingleton ()
   {
   }
}

At the time, I was thrilled. I was able to create a singleton using the famous recursive pattern that made C++ templates so weird to understand; all that in C# 2.0. However, I wasn't entirely satisfied with the implementation. So, where's the catch? Read the code again...

One of the tenets for the Singleton pattern existence is that the instance must be unique; that was the property that I wasn't honoring. The requirement that T must implement a public default constructor was killing the design of such a reusable pattern component. It took me like 6 hours of trying this to realize that the design wasn't flawed; it was my usual C++ way of thinking that was hindering me from discovering the solution to this problem.

The solution can be described with just one word: Reflection. Yes, reflection is one of those features that can be extremely powerful when used correctly, or a "Golden Hammer" if used carelessly. In this case, reflection was the feature that would allow me to honor the most important property of Singletons and at the same time to do some runtime checking on behalf of the user of a generic library.

C#
ConstructorInfo constructor = typeof(T).GetConstructor(
   BindingFlags.Instance | BindingFlags.NonPublic,
   null, new Type[0],
   new ParameterModifier[0] );

   if (constructor == null)
      throw new Exception("The singleton doesnt" + 
            " have a private/protected constructor.");

   try
   {
      allocator = constructor.Invoke(new object[0]) as T;
   }
   catch (Exception e)
   {
      throw new Exception("The Singleton couldnt be constructed", e);
   }

Now, instead of relaying on the new() constraint in the generic type, by reflection, we would only look for private or protected constructions. That means that, if a user mistakenly tries to create a singleton and add a default constructor that isn't private or protected, then the singleton base would not allow it to continue raising an exception (this implementation does not check if the user adds public constructors with parameters, but that is easily achieved).

Up to that point I was pretty satisfied with the solution, but having different styles of singleton behaviors like lazy allocation, configuration based, etc., would require me to recode the singletons. I know what you think, I don't like it either.

Allocator Based Singleton

Until now, I talked about the "Generic Singleton" and how to achieve such an artifact without partial specialization templating (also known as full blown C++ templating engine). Now, I'll focus on allocators, what they do, what their responsibility is, what we can do with them, and maybe some little history about their existence.

Allocators, in one shape or another, can be tracked to the very beginning of the programming endeavour. There had always been a necessity to allocate resources, and the most basic resource to allocate was memory; so in procedural languages, we relied either on the compiler to do stack allocation of memory, or on specific constructions or library calls (as in C) to do the work. Using those approaches, the specific allocation strategy was hidden from the programmer by those calls.

Sometimes things didn't work as expected, and those default allocation strategies fell short, mostly when a lot of space had to be allocated to be used in special ways; for example, in mathematical code (memory must be aligned and consecutive to better use the processor's cache) or in code with high performance requirements. Under such circumstances, most programmers relied on custom strategies to handle those situations, doing just a single call to get all memory required in one step.

When object orientation got mainstream with languages like Smalltalk and C++, some objects were a little too big and costly to initialize, so we relied again on allocators to recycle the memory we used or the objects.

Then someone thought, what if we let the programmer specify the memory/object allocation strategy, giving a binding to the underlying allocation system. Then, the allocators where given a name and an existence of their own. And, light filled the sky and allocators where born.

OK, enough history. Now, we are going to the nitty gritty details (I love this part). In my opinion, the best way to accomplish something is knowing where we want to go. Now, let's suppose we have our "Static Allocation Singleton" from the first part, so... what if we write something like this:

C#
/// <summary>
/// An StaticSingleton using an StaticAllocator used just 
/// to simplify the inheritance syntax.
/// </summary>
public class StaticSingleton<T> : Singleton<T, 
             StaticAllocator<T>> where T : class
{
}

So, our static singleton is just a Singleton of type T with a StaticAllocator of type T. Cool, isn't it? Now, let's get our hands dirty. By now, we know that our allocators will be the ones that will be in charge of specifying our allocation strategy. Now our singleton not only depends on T, but on our Allocator too. In the C# code, it should be something like this:

C#
public class Singleton< T, Allocator >
   where T : class
   where Allocator : Allocator< T >
{
   private static readonly Allocator<T> allocator;
   /// <summary>
   /// The Singleton implementation of the
   /// Instance method defer the creation policy to
   /// its allocator, so this method just delegate
   /// the Instance retrieval to the
   /// Instance method of the allocator.
   /// </summary>
   public static T Instance
   {
      get { return allocator.Instance; }
   }
}

Even if you don't know it already, we have solved the Allocator Based Singleton problem. "Where is the trick?", you might be thinking. Well, someone said (if anyone knows the source, it would be cool): "There are only a few problems in Computer Science that cannot be solved by an extra level of indirection". I applied that concept, so now the Instance method just delegates the real allocation to the Allocator instance.

We have a big problem to solve yet, but we have solved it in the last singleton implementation. Guess who had been the lucky winner that will ensure that the allocator gets created? Yes, our friend Reflection.

C#
static Singleton()
{
   ConstructorInfo constructor = typeof(Allocator).GetConstructor(
      BindingFlags.Instance | 
      BindingFlags.NonPublic, null, 
      new Type[0], new ParameterModifier[0] );

   if (constructor == null)
      throw new Exception("The allocator doesnt " + 
            "have a private/protected constructor.");

   try
   {
      allocator = constructor.Invoke(new object[0]) as Allocator<T>;
   }
   catch (Exception e)
   {
      throw new Exception("The Singleton Allocator couldnt be constructed", e);
   }
}

What if I create multiple allocators? Can I then create multiple instances of T? The answer is yes and no. Yes, you can create multiple instances of the allocator, and, no, they won't allow you to have multiple instances of T using the same trick that we used before.

Our allocator looks like this:

C#
public abstract class Allocator<T>
   where T : class
{
   /// <summary>
   /// The parameterless protected Constructor.
   /// </summary>
   protected Allocator()
   {
   }

   /// <summary>
   /// The property returns the only instance
   /// of the Singleton Object in question.
   /// </summary>
   /// <remarks>This property implementation
   /// must enforce the Single Object property
   /// of Singletons throwing an exception.</remarks>
   public abstract T Instance { get; }
}

So how does our StaticAllocator look? Well, almost the same as our original singleton:

C#
public class StaticAllocator<T> : Allocator<T> where T : class
{
   static StaticAllocator()
   {
      ConstructorInfo constructor = typeof(T).GetConstructor(
          BindingFlags.Instance |
          BindingFlags.NonPublic, null,
          new Type[0], new ParameterModifier[0] );

      if (constructor == null)
         throw new Exception("The object doesnt" + 
               " have a private/protected constructor.");

      try
      {
         instance = constructor.Invoke(new object[0]) as T;
      }
      catch (Exception e)
      {
         throw new Exception("The StaticSingleton couldnt be constructed", e);
      }
   }

   private StaticAllocator()
   {
   }

   private static readonly T instance;

   /// <summary>
   /// The static allocator Instance property
   /// returns the instance created on class loading.
   /// </summary>
   /// <remarks>This means that the singleton is instantiated at the moment in which
   ///  a class has a reference to that type even if it never calls the Instance
   ///  method.</remarks>
   public override T Instance
   {
      get { return instance; }
   }
}

What if we want to do a LazyAllocator? Well, as in most textbooks, we will leave that for the readers to implement by themselves (just don't tell anyone, you can get the source right from here). So, we did all this just to implement a LazyAllocator? Hell, no! What if I say that you can have an abstract singleton to instantiate a concrete provider by itself, just by reading the concrete instance from a config file? Would it be useful? Well, I know of a specific scenario where it will not only be cool, but also useful. When you are creating a Rendering Engine and the rendering provider could be Managed DirectX or OpenGL (and that can't be changed on the fly), then you just read the Renderer concrete class from a configuration file, and the user won't ever know what it is using as it is using an abstract class.

I must say that this article was fun to write, so I hope you enjoyed reading it as much as I did writing it.

Note: This article has been originally published in my personal blog, you can leave your comments either here or there.

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


Written By
Founder Corvalius
Argentina Argentina
Founder of Corvalius (http://www.corvalius.com). He is the Lead Architect of Beweevee Live Collaboration Technology (http://www.beweevee.com). Has a degree on Computer Science from the Universidad Nacional del Sur at Bahia Blanca. His research interests are real-time graphics, distributed systems and parallel computing, especially on data parallel architectures (GPGPU).

Formerly part of the Huddle's Group Core Technologies Team, specialized in consulting in areas like high performance computing, systems integration and scientific visualization. Frequent speaker at local conferences on technology. He also presented at the Demofest at the Microsoft Research Faculty Summit 2009 at Argentina.

Avid reader, counting along 40 books in the last year ranging from topics like Mathematical Uncertainty to Business and Behavioral Finance.

He also has been project leader from 2003 to 2006 on Project Xenocide (formerly XComUfo), an open source game that at the time has been named among the 10 most promising Open Source games by the April's 2003 issue of the Computer Games Magazine.

More details can be found at: http://ar.linkedin.com/in/federicolois

Comments and Discussions

 
Praisegreat info Pin
Southmountain2-Apr-22 17:27
Southmountain2-Apr-22 17:27 
GeneralVery helpful article Pin
dmitrygrig12-Aug-12 4:46
dmitrygrig12-Aug-12 4:46 
GeneralI am not quite following this Pin
mjmeans1-Apr-09 23:30
mjmeans1-Apr-09 23:30 
GeneralRe: I am not quite following this Pin
Federico Andres Lois27-Aug-10 5:34
Federico Andres Lois27-Aug-10 5:34 
Generalgood article Pin
Donsw15-Feb-09 13:36
Donsw15-Feb-09 13:36 
QuestionLicense Pin
Ondrej Skrehota17-Jul-08 5:50
Ondrej Skrehota17-Jul-08 5:50 
AnswerRe: License Pin
Daniel C.11-Jun-09 19:04
Daniel C.11-Jun-09 19:04 
GeneralRe: License Pin
Federico Andres Lois27-Aug-10 5:17
Federico Andres Lois27-Aug-10 5:17 
GeneralRe: License Pin
Daniel C.3-Sep-10 15:04
Daniel C.3-Sep-10 15:04 
AnswerRe: License Pin
Federico Andres Lois27-Aug-10 5:17
Federico Andres Lois27-Aug-10 5:17 
QuestionOK, silly question Pin
xirisjohn21-Apr-08 4:02
xirisjohn21-Apr-08 4:02 
AnswerRe: OK, silly question Pin
xirisjohn21-Apr-08 10:33
xirisjohn21-Apr-08 10:33 
GeneralGarbage Collection Pin
PuneWala9-Dec-07 22:57
PuneWala9-Dec-07 22:57 
GeneralRe: Garbage Collection Pin
Federico Andres Lois27-Aug-10 5:37
Federico Andres Lois27-Aug-10 5:37 
GeneralQuote Pin
el_dricos8-Nov-07 0:14
el_dricos8-Nov-07 0:14 
GeneralRe: Quote Pin
Federico Andres Lois8-Nov-07 17:32
Federico Andres Lois8-Nov-07 17:32 
QuestionIs there a similar solution for VB.NET available ? Pin
lotharbehrens20-Feb-07 3:15
lotharbehrens20-Feb-07 3:15 
AnswerRe: Is there a similar solution for VB.NET available ? Pin
Federico Andres Lois5-Mar-07 2:22
Federico Andres Lois5-Mar-07 2:22 
QuestionCheck for public constructors [modified] Pin
mikl-dk7-Dec-06 21:27
mikl-dk7-Dec-06 21:27 
AnswerRe: Check for public constructors Pin
Federico Andres Lois8-Dec-06 9:43
Federico Andres Lois8-Dec-06 9:43 
GeneralVery cool but... Pin
sadavoya21-Nov-06 8:57
sadavoya21-Nov-06 8:57 
AnswerRe: Very cool but... Pin
Federico Andres Lois27-Nov-06 7:33
Federico Andres Lois27-Nov-06 7:33 
Generalboring Pin
noemailz21-Nov-06 8:27
noemailz21-Nov-06 8:27 
GeneralRe: boring Pin
Daniel Turini23-Nov-06 22:55
Daniel Turini23-Nov-06 22:55 
GeneralRe: boring Pin
NormDroid26-Feb-07 23:18
professionalNormDroid26-Feb-07 23:18 

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.