JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

Singleton Pattern

Here is the ubiquitous Singleton Pattern that restricts the creation to a single instance of a class. This pattern is useful as it:

  1. Adds a level of indirection. This allows the creation of more than one instance of the class at a later date without breaking client code.
  2. Encapsulates data and methods into a separate namespace, the singleton class. 
  3. Allows sub-classing. 
  4. Provides access control to the single instance. 

If you do not need the added level of indirection provided by the Singleton Pattern, it may be simpler to use static methods and fields. You can see the similarities between using the Singleton Pattern and using static methods and fields by comparing the IL generated by similar projects. 

Both projects create very similar DoIt() stack frames, but the Singleton Pattern adds a pointer to this to the stack frame. Here is the static DoIt() IL:

Static : DoIt : void()

.method private hidebysig static void  DoIt() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  ldsfld     string TestILStatic.Class1::message
  IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000a:  ret
} // end of method Class1::DoIt

Here is the Singleton DoIt() IL:

Singleton : DoIt : void()

.method public hidebysig instance void DoIt() cil managed
{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld string TestILSingleton.Singleton::message
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: ret
} // end of method Singleton::DoIt

Note the added argument on the stack to this.

Calling DoIt() in Main is more straightforward in the static approach. Here is the IL from the static project:

Static : Main : void(string[])

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       7 (0x7)
  .maxstack  0
  IL_0000:  call       void TestILStatic.Class1::DoIt()
  IL_0005:  nop
  IL_0006:  ret
} // end of method Class1::Main

Now note the added IL instructions using the Singleton Pattern:

Singleton : Main : void(string[])

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
// Code size 13 (0xd)
.maxstack 1
.locals init ([0] class TestILSingleton.Singleton s)
IL_0000: call class TestILSingleton.Singleton TestILSingleton.Singleton::GetInstance()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void TestILSingleton.Singleton::DoIt()
IL_000c: ret
} // end of method Singleton::Main

Both approaches produce stack frames for the fields. Here is the static IL:

Static : .cctor : void()

.method private hidebysig specialname rtspecialname static 
        void  .cctor() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  ldstr      "Hello World!"
  IL_0005:  stsfld     string TestILStatic.Class1::message
  IL_000a:  ret
} // end of method Class1::.cctor

Again, the Singleton Pattern generates more complicated IL:

Singleton : .ctor : void()

.method private hidebysig specialname rtspecialname 
instance void .ctor() cil managed
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldstr "Hello World!"
IL_0006: stfld string TestILSingleton.Singleton::message
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: ret
} // end of method Singleton::.ctor

By looking at IL generated by the Singleton Pattern and a similar project using static methods and fields, you can see that at the IL level, the code is similar, but more complicated in the project using the Singleton Pattern. The extra complexity of the Singleton Pattern does add a level of indirection. If your project does not make use of this extra level of indirection, you may be able to just use static methods and fields.

C# Source Code

using System;
namespace TestILSingleton
{
	class Singleton 
	{
		private static Singleton s= new Singleton();
		static Singleton GetInstance() 
		{
			return s;
		}	
		private string message= "Hello World!";
		public void DoIt() 
		{
			System.Console.WriteLine(message);
		}
		private Singleton() {;}
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			//
			// TODO: Add code to start application here
			//
			Singleton s= GetInstance();
			s.DoIt();
			//System.Console.ReadLine();
		}
	}
}

Common Intermediate Language Code

.class private auto ansi beforefieldinit

.class private auto ansi beforefieldinit Singleton
extends [mscorlib]System.Object
{
} // end of class Singleton

message : private string

.field private string message

s : private static class TestILSIngleton.Singleton

.field private static class TestILSingleton.Singleton s

.cctor : void()

.method private hidebysig specialname rtspecialname static 
void .cctor() cil managed
{
// Code size 11 (0xb)
.maxstack 1
IL_0000: newobj instance void TestILSingleton.Singleton::.ctor()
IL_0005: stsfld class TestILSingleton.Singleton TestILSingleton.Singleton::s
IL_000a: ret
} // end of method Singleton::.cctor

.ctor : void()

.method private hidebysig specialname rtspecialname 
instance void .ctor() cil managed
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldstr "Hello World!"
IL_0006: stfld string TestILSingleton.Singleton::message
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: ret
} // end of method Singleton::.ctor

DoIt : void()

.method public hidebysig instance void DoIt() cil managed
{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ldfld string TestILSingleton.Singleton::message
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: ret
} // end of method Singleton::DoIt

GetInstance : class TestILSingleton.Singleton()

.method private hidebysig static class TestILSingleton.Singleton 
GetInstance() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init ([0] class TestILSingleton.Singleton CS$00000003$00000000)
IL_0000: ldsfld class TestILSingleton.Singleton TestILSingleton.Singleton::s
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method Singleton::GetInstance

Main : void(string[])

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
// Code size 13 (0xd)
.maxstack 1
.locals init ([0] class TestILSingleton.Singleton s)
IL_0000: call class TestILSingleton.Singleton TestILSingleton.Singleton::GetInstance()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void TestILSingleton.Singleton::DoIt()
IL_000c: ret
} // end of method Singleton::Main
 
Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1