| « Bonjour MEF | Last codeplex project address change » |
Concrete Singleton pattern implementation in .NET
Hello everybody,
A pattern we regularly find is the singleton pattern. What I suggest you is a .NET implementation. This one deals with a singleton context dependent (singleton by ASP.NET context, by WCF context, by thread, for the whole application)
public class Singleton<T>
{
private Singleton()
{
if (CreatingInstance != null)
CreatingInstance(this, EventArgs.Empty);
}
private static T instance;
[ThreadStatic]
private static T threadInstance;
private static object instanceLock = new object();
public static T Instance
{
get
{
//ASP.NET case
T instance;
if (HttpContext.Current != null)
{
if (UseContextInstance)
instance = (T)HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
else
instance = (T)HttpContext.Current.Application[typeof(T).AssemblyQualifiedName];
if (instance == null)
{
instance = new Singleton<T>().SingletonInstance;
if (UseContextInstance)
HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = instance;
else
HttpContext.Current.Application[typeof(T).AssemblyQualifiedName] = instance;
}
return instance;
}
if (OperationContext.Current != null)
{
throw new NotImplementedException();
if (instance == null)
{
HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = new Singleton<T>().SingletonInstance;
}
return instance;
}
//In case of no HttpContext nor OperationContext
if (UseContextInstance)
{
if (Singleton<T>.threadInstance == null)
Singleton<T>.threadInstance = new Singleton<T>().SingletonInstance;
}
else
{
if (Singleton<T>.instance == null)
{
lock (instanceLock)
{
if (Singleton<T>.instance == null)
Singleton<T>.instance = new Singleton<T>().SingletonInstance;
if (Singleton<T>.instance == null)
TryActivate(out Singleton<T>.instance);
}
}
}
return Singleton<T>.instance;
}
}
private static void TryActivate(out T p)
{
try
{
p = Activator.CreateInstance<T>();
}
catch (MissingMethodException) { p = default(T); }
}
public T SingletonInstance { get; set; }
public static event EventHandler CreatingInstance;
/// <summary>
/// Set this property to <see cref="true" /> to have your singleton dependant on your context :
/// - one per thread in Windows Forms/WPF
/// - one per Context in ASP.NET
/// </summary>
public static bool UseContextInstance { get; set; }
}
3 comments
First, the class is not thread safe (you're not locking much and in some cases the singleton can be created several times).
The static event is a synchronisation failure waiting to happen (no lock on add-remove... nasty things may happen if a subscriber unsubscribes just before you raise CreateInstance).
This implementation also have hard coded dependencies on system.web.dll (asp.net) and system.servicemodel.dll (wcf) which makes it very context specific.
Furthermore, singletons with different lifestyles (i.e. different lifecycles) are mostly a problem solved now if you use any decent IoC framework (see lifestyles in Castle Windsor for instance).
You're also right for the hard coded dependencies. What I assumed and did not explained is that this class is supposed to be used in a base class library. So you are not supposed to have any issue with this because these libraries (system.web and system.servicemodel) are both in the GAC).
Interesting approach but as Yann said, you should have a look at how IoC Containers deal with such things as lifecycle, lifestyle, component activation ... Castle Windsor being a great example of those principles dealt with in a loosely-coupled fasion.
Comments are closed for this post.