mcgarrybowen, New York
- 601 West 26th Street Suite 1150
- New York, New York 10001
- United States
- Phone: 212 598 2900
- Fax: 212 598 2996
- Country Phone Code: 1
- Email: info@mcgarrybowen.com
Inheriting Singleton Pattern in C# with Self-referencing Type Constraint
October 10, 2012
Everyone knows the singleton pattern. I’ve often found that when you ask a junior developer about design patterns in an interview, they will immediately tout the singleton pattern. Design patterns? Sure: Singleton, check. Not so fast. First, if singleton pattern is your only go-to design patterns answer, spend a little more time googling “design patterns.” Second, how do you implement it? This question can get a different answer from probably every different developer asked. Leaving aside discussions of when you should use an IoC container instead to lock down access to an object instance and enforce single instantiation (or some other mechanism altogether), let’s consider a few different implementations of the singleton pattern (in C#).
The most basic implementation involves a class with a private static member variable to hold the instance and a public static GetInstance method (or property) of some sort. Usually, the developer will say something about threading and needing to perform locking to prevent multiple instances from being created by different threads executing in parallel. Great, so maybe they’ve even read the MSDN article on singletons (http://msdn.microsoft.com/en-us/library/ff650316.aspx) and will quote letter for letter this implementation:
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Great, and maybe they’ve even seen this excellent singleton article (http://www.yoda.arachsys.com/csharp/singleton.html) and can explain the virtues of using a static class. If you can get thread-safety for free (as you can by using a static class), then please don’t ever try to attack threading yourself. You won’t wind up in a world of hurt–the guy maintaining the code after you leave will wind up in that world of hurt. At this point, if the interviewee knows what beforefieldinit is, what it does, and why it’s important for static class singletons, then they’ve won the point.
There are, however, reasons to argue for using non-static classes–most obviously: inheritance. Just because a class should not be multiply-instantiated does not also mean that it should not be able to inherit methods that it shares with other classes. Furthermore, maybe I’m lazy and don’t want to write out the code sample for every singleton I create–maybe I want to inherit the logic for the singleton pattern from a singleton base class.
For a real world example, let’s consider the repository pattern. (Before you start, yes, always use an ORM, preferably EF, if you are using .NET–don’t reinvent the data access wheel.) In this case, data access is happening against XML files. Each XML file is roughly analogous to a table of objects, so we’ll have a repository for each object type that reads from its own XML file. To reduce file I/O, and because the data sets are relatively small (<5 MB), we will read in each XML file and store its deserialized objects in memory for the life of the application pool (writes need not be considered). Although the footprint of holding this data in memory is small, multiple=”multiple” instances could start to consume a lot of memory quickly (not to mention increase file I/O)–so we need to enforce single instantiation. But wait, there’s more! Since we will have multiple=”multiple” repositories, not only do we not want to duplicate the singleton logic, but we also do not want to duplicate the logic to deserialize the XML files and load the object lists into memory.
This brings us to the crux of the issue–inheriting singleton pattern logic in C# which also secondarily allows for other common logic to be inherited across related singletons. In order to do this, we need to address two issues. First, the GetInstance method (or Instance property) has to be implemented in a base class. Second, from the context of this base class, we need to ascertain what is the derived type for which we need to return an instance. The first point is trivial, the second gets tricky.
In PHP, we can use the get_called_class method to determine the derived class type from within a base class a la:
abstract class Repositories_RepositoryBaseAbstract
{
protected static $_instances = array();
final private function __construct() { }
final private function __clone() { }
final public static function &getInstance()
{
$calledClass = get_called_class();
if(array_key_exists($calledClass, static::$_instances) && null !== static::$_instances[$calledClass]){
return static::$_instances[$calledClass];
}
static::$_instances[$calledClass] = new $calledClass();
return static::$_instances[$calledClass];
}
}
So what is the get_called_class equivalent for C#? Well, that’s where self-referencing type constraints come into play. Play close attention to the types “ProductRepository” and “RepoType.”
public class ProductRepository : BaseRepository<Product, ProductRepository>, IProductRepository
{
// Ideally, convention over configuration would absolve us from having
// to specify this for each repo, but whatever...
public override string GetXmlFileName()
{
return "Product.xml";
}
}
public abstract class BaseRepository<T, RepoType>
where RepoType : BaseRepository<T, RepoType>, new()
{
private static object syncRoot = new Object();
private static object _instance;
internal BaseRepository()
{
this.LoadXmlData();
}
public static RepoType GetInstance()
{
if (_instance == null)
{
lock (syncRoot)
{
if (_instance == null)
_instance = new RepoType();
}
}
return (RepoType)_instance;
}
// Inheritance FTW
protected abstract string GetXmlFileName();
protected virtual void LoadXmlData()
{
// Common, inherited logic that isn't related to the singleton pattern implementation
// I'm going to use my T type here when deserializing--abstraction FTW
}
}
In this example, “where RepoType : BaseRepository<T, RepoType>” on the BaseRepository class is a self-referencing type constraint. It says that RepoType has to derive from this base class because it’s constrained to implement the same type signature as the base class itself. Mull that over for a second. Now when the derived class is declared, you just have to pass the derived type as the generic type for “RepoType” and then the base class will know that RepoType is the derived type. Re-read this paragraph (but don’t get stuck in an infinite loop).
With this self-referencing type constraint mechanism in your tool belt, you can now ascertain the derived type of a class from a base class–which is all that you need to inherit singleton pattern logic without having to constantly cast the returned instance to the proper derived type in all of your client code. And having to specify the derived type as a generic type to the base class at design-time is much less code than having to type-cast everywhere or rewrite singleton pattern logic everywhere.
The end.