mercredi 14 janvier 2009

Implémentation concrète du pattern Singleton en .NET

Bonjour à tous,

Un pattern que l'on retrouve assez régulièrement est le pattern singleton, je vous propose ici une implémentation .NET. Celle ci gère le fait que l'on veuille un singleton dépendant d'un contexte ou non (singleton par contexte ASP.NET, singleton par contexte WCF, singleton par Thread, singleton pour une application ASP.NET) :


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; }
}

Aucun commentaire: