I was attending the “Microsoft patterns and practices” lectures the other day when the subject of the singleton pattern came up.
One of the questions a friend asked, which weren’t discussed at the time, was: “Why would I want to use the singleton pattern when I can simply declare all the methods and variables in my class as static?”
Well, of course you can. If you have a self contained class that doesn’t have any special initialization. Something like:
public class Test1
{
static int someValue = 100;
static public int someMethod()
{
return someValue;
}
static Test1()
{
System.Console.WriteLine(“Test1 static constructor”);
}
}
Test1 is a simple self contained class with a static constructor. The static constructor will be called right before the first use of the static class.
So if we have something like:
|
System.Console.WriteLine("First Line");
System.Console.WriteLine(Test1.someMethod()); |
The output will be:
|
First Line
Test1 static constructor
100 |
You might have already spotted the problem with static classes, copy and paste the following code into your IDE, check if you can see what the output should be before running it:
public class A
{
public static string staticVariableCopiedFromB = B.staticVariable;
public static string staticVariable = "Thing is a string defined in A";
}
public class B
{
public static string staticVariableCopiedFromA = A.staticVariable;
public static string staticVariable = "Thing is a string defined in B";
}
public class Test
{
static void Main(string[] args)
{
System.Console.WriteLine(A.staticVariableCopiedFromB);
System.Console.WriteLine(B.staticVariableCopiedFromA);
}
}
The output you should get is:
|
Thing is a string defined in B |
Why is this happening? Lets look at what the JIT compiler is doing:
- A is being called, so start initializing A
- The static variable in A needs a value from B, so start initializing B
- B needs a static value in A, which isn’t set yet
This prevents infinite circular initialization.
Changing the order so that the string assignment happens before the static assignment from the other class resolves the issue:
public class A
{
public static string staticVariable = "Thing is a string defined in A";
public static string staticVariableCopiedFromB = B.staticVariable;
}
public class B
{
public static string staticVariable = "Thing is a string defined in B";
public static string staticVariableCopiedFromA = A.staticVariable;
}
An even better way is to use the static constructor to explicitly initialize it in the correct order:
public class A
{
public static string staticVariable;
public static string staticVariableCopiedFromB;
static A()
{
staticVariable = "Thing is a string defined in A";
staticVariableCopiedFromB = B.staticVariable;
}
}
public class B
{
public static string staticVariable;
public static string staticVariableCopiedFromA;
static B()
{
staticVariable = "Thing is a string defined in B";
staticVariableCopiedFromA = A.staticVariable;
}
}
The compiler will actually generate the static constructors itself; it just feels safer to do it explicitly.
That might have been an elegant solution for a very small example, but can you see what will happen when we start working with 5 or more classes with dependencies.
This is why we can’t always depend on the order of static initialization. By explicitly initializing our singleton classes we can be sure that someone doesn’t destroy our carefully crafted static initialization bootstrap code by accidentally calling something when it shouldn’t be. As you can see, there isn’t a compile or run time error, just an unexpected result, these problems can be very difficult to track down.
Please drop a comment if I’m missing something or unaware of a dot net specific feature.