public class CustomerManager
{
private static volatile CustomerManager _instance;
private static object syncRoot = new Object();
private CustomerManager()
{
}
public static CustomerManager Current
{
get
{
if (_instance == null)
{
lock (syncRoot)
{
if (_instance == null)
{
_instance = new CustomerManager();
}
}
}
return _instance;
}
}
}
泛型化后的代码:
using System;
using System.Reflection;
namespace EPMPortal
{
/// <summary>
/// Manages the single instance of a class.
/// </summary>
/// <remarks>
/// Generic variant of the strategy presented here : http://geekswithblogs.net/akraus1/articles/90803.aspx.
/// Prefered to http://www.yoda.arachsys.com/csharp/singleton.html, where static initialization doesn't allow
/// proper handling of exceptions, and doesn't allow retrying type initializers initialization later
/// (once a type initializer fails to initialize in .NET, it can't be re-initialized again).
/// </remarks>
/// <typeparam name="T">Type of the singleton class.</typeparam>
public static class Singleton<T>
where T : class
{
#region Fields
/// <summary>
/// The single instance of the target class.
/// </summary>
/// <remarks>
/// The volatile keyword makes sure to remove any compiler optimization that could make concurrent
/// threads reach a race condition with the double-checked lock pattern used in the Instance property.
/// See http://www.bluebytesoftware.com/blog/PermaLink,guid,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx
/// </remarks>
static volatile T _instance;
/// <summary>
/// The dummy object used for locking.
/// </summary>
static object _lock = new object();
#endregion Fields
#region Constructors
/// <summary>
/// Type-initializer to prevent type to be marked with beforefieldinit.
/// </summary>
/// <remarks>
/// This simply makes sure that static fields initialization occurs
/// when Instance is called the first time and not before.
/// </remarks>
static Singleton()
{
}
#endregion Constructors
#region Properties
/// <summary>
/// Gets the single instance of the class.
/// </summary>
public static T Instance
{
get
{
if (_instance == null)
lock (_lock)
{
if (_instance == null)
{
ConstructorInfo constructor = null;
try
{
// Binding flags exclude public constructors.
constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], null);
}
catch (Exception exception)
{
throw new SingletonException(exception);
}
if (constructor == null || constructor.IsAssembly) // Also exclude internal constructors.
throw new SingletonException(string.Format("A private or protected constructor is missing for '{0}'.", typeof(T).Name));
_instance = (T)constructor.Invoke(null);
}
}
return _instance;
}
}
#endregion Properties
}
}
namespace EPMPortal
{
/// <summary>
/// Represents errors that occur while creating a singleton.
/// </summary>
/// <remarks>
/// http://msdn.microsoft.com/en-us/library/ms229064(VS.80).aspx
/// </remarks>
[Serializable]
public class SingletonException
: Exception
{
/// <summary>
/// Initializes a new instance.
/// </summary>
public SingletonException()
{
}
/// <summary>
/// Initializes a new instance with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public SingletonException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance with a reference to the inner
/// exception that is the cause of this exception.
/// </summary>
/// <param name="innerException">
/// The exception that is the cause of the current exception,
/// or a null reference if no inner exception is specified.
/// </param>
public SingletonException(Exception innerException)
: base(null, innerException)
{
}
/// <summary>
/// Initializes a new instance with a specified error message and a
/// reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">
/// The exception that is the cause of the current exception,
/// or a null reference if no inner exception is specified.
/// </param>
public SingletonException(string message, Exception innerException)
: base(message, innerException)
{
}
#if !WindowsCE
/// <summary>
/// Initializes a new instance with serialized data.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/> that holds the
/// serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/> that contains
/// contextual information about the source or destination.
/// </param>
/// <exception cref="System.ArgumentNullException">The info parameter is null.</exception>
/// <exception cref="System.Runtime.Serialization.SerializationException">The class name is null or System.Exception.HResult is zero (0).</exception>
protected SingletonException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}