Introduction
Many articles have been written about the Singleton design pattern and there
have been a few on how to implement it in .NET. This article is not intended to
be a restatement of those. Instead I want to describe a solution to a problem
that occurred to me soon after reading Microsoft's recommended implementation
of the Singleton pattern in .NET. The Microsoft solution was published in
February 2002, titled
Exploring the Singleton Design Pattern. Here it is:
sealed class Singleton
{
private Singleton() {}
public static readonly Singleton Instance = new Singleton();
}
The traditional solution, as originally elaborated in Java, uses a technique
called "double-check locking" in order to address thread safety. When
translated to C# it looks like this:
class Singleton
{
public static Singleton Instance()
{
if (_instance == null)
{
lock (typeof(Singleton))
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
protected Singleton() {}
private static volatile Singleton _instance = null;
}
For a full discussion and explanation of the issues, and the above two
solutions, please refer to the Microsoft article. Needless to say, Microsoft's
recommended solution is far simpler than the traditional solution. But a
problem occurred to me...
The Problem
What happens if I want to perform initialization of the singleton at
construction time? Well, in the traditional solution I can just overload the
Instance()
method to take parameters and this will delegate to an
overloaded protected constructor. So, for example, if I have a single WebMaster
object, I can write:
WebMaster webMaster = WebMaster.Instance("Kevin", "McFarlane");
However, with the recommended solution I can't do this. Instance
is
a read-only field, not a method, so I can't parameterize it. I'd been thinking
about this on and off for some time before I came up with
a reasonable solution. But I would be interested in seeing alternative
solutions.
At first I thought that the only way to do this was to make two separate calls
along the following lines:
WebMaster webMaster = WebMaster.Instance;
webMaster.Create("Kevin", "McFarlane");
But this kind of thing is never ideal for a client. It's always preferable to
have an object fully constructed at creation time. Or, if this is not possible,
and further initialization needs to be done, this should be hidden from the
client. Well, in the end, we can't really do this but we can improve matters.
And the solution was virtually staring me in the face in the Microsoft example
showing how to apply the recommended solution. Essentially we just arrange
things so that the two separate calls can be combined into one. So, at least it
looks like we're doing parameterized construction. Here's how:
sealed class WebMaster
{
public static readonly WebMaster Instance = new WebMaster();
public WebMaster Create(string firstName, string lastName)
{
_firstName = firstName;
_lastName = lastName;
return Instance;
}
public string FirstName
{
get
{
return _firstName;
}
}
public string LastName
{
get
{
return _lastName;
}
}
private WebMaster() {}
private string _firstName;
private string _lastName;
}
The Create
method serves as a "parameterized constructor." We can
now write code such as the following, which is more concise:
WebMaster webMaster = WebMaster.Instance.Create("Kevin", "McFarlane");
Console.WriteLine("First Name = " + webMaster.FirstName);
Console.WriteLine("Last Name = " + webMaster.LastName);
Further Issues
If we wish to prevent multiple initialization through calling Create
more than once we can just add an internal flag to indicate whether the
instance has been "created" or not and raise an exception if it has.
But what if we wish to have only parameterized construction? That is,
what if we want to guarantee at compile time that the instance is
created in an initialized state? For example, suppose all instances of WebMaster
must have their name properties set. I can't see a way of doing this other than
by documentation. We can do better at runtime.
We could make every public routine, such as LastName
, check a flag
and then raise an exception if WebMaster
hasn't been
initialized.
This is something that can be done using conditionally compilable
precondition checking that we might disable for a release build.
Alternatively, if WebMaster
hasn't been initialized the fields
will be null. So when a client tries to use the name properties it will soon
notice that they haven't been set.
The latter approach is cleaner and simpler. We don't have to do anything. The
former approach means more work but it has the advantage that the specification
is made explicit and verifiable in code.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.