About Me

Please see my LinkedIn profile for more information about me (http://www.linkedin.com/in/kevinwhitemmlsolutions).

Technology

Wednesday, January 7, 2009

Generic implementation of the Singleton design pattern in C#

I am presently creating a library of reusable code and have several service classes that would be appropiatly implemented as singletons. However rather than implementing the singleton pattern on a class by class basis I wanted a way of reusing a generic class that would allow me to make any class a singleton. Generics and reflection allow this to be achieved in .NET.

The Design
The following fragment of a UML static diagram shows the design of Singleton class.


Points of note:
  • Generic class with parameter T
  • Instance is referenced by the static generic member singletonInstance
  • The static method GetInstance returns the singleton instance or constructs an instance if one has not already been instantiated (lazy instantiation)
  • The static Reinitialize method simply sets the singleton reference to null and invokes GerInstance (causing the state to be reset which could be important for some types of singletons)
  • The methods GetInstance and Reinitialize use the lock statement to ensure thread-safety
The Code

/// <summary>
/// Provides an implementation of the Singleton design pattern. This can be used
/// for resource type objects such as exception handlers.
/// </summary>
/// <typeparam name="T">The type that inherits and hence implements the Singleton design pattern</typeparam>
public abstract class Singleton<T> where T:class
{
#region STATIC DATA MEMBERS
/// <summary>
/// The single instance of the subclass
/// </summary>
private static T singletonInstance;

/// <summary>
/// Object instance is used for concurrency control
/// </summary>
private static readonly object lockingObject = new object();
#endregion


#region STATIC METHODS
/// <summary>
/// Returns the instance of the class that derives from this class or creates an
/// instance if one does not already exist.
/// </summary>
/// <returns>The instance of the class derived from Singleton</returns>
public static T GetInstance()
{
lock (lockingObject)
{
if (SingletonInstance == null)
{
// Use reflection to instantiate a new instance of the class T. This
// is required as instantiating a new instance directly (new T) would
// violate the basic principle of why the sinleton pattern is used as there
// would have to be a public constructor
SingletonInstance = UtilityHelper.ConstructParameterlessInstanceOfType<T>(BindingFlags.Instance | BindingFlags.NonPublic);
}
}

return SingletonInstance;
}


/// <summary>
/// Gets the single instance of the sub-class that derives from this Singleton
/// </summary>
protected static T SingletonInstance
{
get
{
return singletonInstance;
}
set
{
singletonInstance = value;
}
}

/// <summary>
/// Re-initializes the singleton instance by causes the instance to be instantiated
/// as a new instance. This can be used, for example, when changes to configuration
/// have been made.
/// </summary>
/// <returns>A new instance of the type that sub-classes from this type</returns>
public static T Reinitialize()
{
lock (lockingObject)
{
SingletonInstance = null;
}

return GetInstance();
}
#endregion
}

An can be seen from the code, if an instance of the type that does exist than a
new instance is created by invoking the private constructor of that type.
The code for this method is shown below:


/// <summary>
/// Constructs a dynamic instance of the type T by invoking the
/// private or protected parameterless contructor of that type. This
/// primarily can be used to instantiate singleton instances (as by
/// definition they must not have a public constructor).
/// </summary>
/// <typeparam name="T">The type to instantiate</typeparam>
/// <returns>An instance of the type T</returns>
public static T ConstructParameterlessInstanceOfType<T>(BindingFlags bindingFlags) where T:class
{
ConstructorInfo constructor = typeof(T).GetConstructor(
bindingFlags,
null,
new Type[0],
new ParameterModifier[0]);

T instance = null;

if (constructor == null)
{
// Type does not have a private or protected parameterless constructor
throw new MemberAccessException(String.Format(CultureInfo.CurrentCulture, "Type {0} does not have the expected constructor (public or private parameterless constructor)", typeof(T).Name));
}
else
{
// Instantiate a new instance of the type by invoking the private or protected constructor
instance = constructor.Invoke(new object[0]) as T;

if (instance == null)
{
throw new MemberAccessException(String.Format(CultureInfo.CurrentCulture, "Unable to create an instance of the type {0}", typeof(T).Name));
}
}

return instance;
}

Singleton derived classes must have a private or protected parameterless constructor.
There is no check for a public constructor but this could easily be added.

Example

The following class demostrates how the is-a relationship can be established
with Singleton.



/// <summary>
/// MicrosoftExceptionHandlingManager provides an exception handling
/// class that is coupled (uses) the Microsoft Patterns & Practices
/// library.
/// </summary>
public class MicrosoftExceptionHandlingManager : Singleton<MicrosoftExceptionHandlingManager>, IExceptionHandlingManager
{
#region CONSTRUCTORS
/// <summary>
/// Private constructor that is required in order for this to be
/// treated as a singleton
/// </summary>
private MicrosoftExceptionHandlingManager()
{
}
#endregion

#region METHODS
/// <summary>
/// Handles an exception by logging it to logging sinks as configured
/// using the Microsoft Enterprise Library V4.0. The specific way an exception
/// is handled can be specified by using the configuration tool that comes
/// supplied with the library.
/// </summary>
/// <param name="ex">The exception to handle</param>
/// <param name="exceptionHandlingPolicy">The policy to use for handling the exception (which relates to the policies in the configuration)</param>
public void LogException(Exception ex, string exceptionHandlingPolicy)
{
bool reThrow = ExceptionPolicy.HandleException(ex, exceptionHandlingPolicy);

if (reThrow == true)
{
throw ex;
}
}
#endregion
}

The two important points about the sample are:

  1. The class is-a Singleton by deriving from Singleton and passing the class name as the type parameter.
  2. The class must have a private or protected constructor.
An example of the code to get a reference to the instance:


MicrosoftExceptionHandlingManager.GetInstance()

Testing Extension Points

  • Performance testing as locking is used
Evolution Extension Points
  • The GetInstance static methods checks that the type T does NOT have a public constructor

Thursday, May 8, 2008

Controlling editability of individual nodes in an Infragistics WebTree (ASP.NET)

Today I came up against the requirement to control the editability of individual nodes of the WebTree class in the Infragistics ASP.NET library. Examining the Node class (server-side) I saw an Enabled property that looked promising. However setting this to false only sets the appearance client-side to disabled but stills allows the node to be editable. Looking around there is no additional server-side or client-side properities to control the editablity. Therefore I came-up with the following work around (after some brief debugging of the Infragistics client-side code!):

Server-side actions:
  1. Set the Enabled property of any nodes that should not be editable to false.
  2. Hook-up the server-side client-side AfterBeginNodeEdit event e.g. tree.ClientSideEvents.AfterBeginNodeEdit = "tree_afterBeginNodeEdit".

Client-side actions:

  1. Provide an event handler for afterBeginNodeEdit e.g.

function tree_afterBeginNodeEdit(treeId, nodeId)
{
var tree = igtree_getTreeById(treeId);
var node = igtree_getNodeById(nodeId);

if(tree != null && node !=null)
{
if(node.getEnabled() == false)
{
tree.endEdit(true);
}
}
}

The two key points here are:

  • Hook up the AfterBeginNodEdit event. Looking at the documentation the BeforeBeginNodeEdit event would be the logically event to handle. However calling the endEdit method in this event does not work as the edit control does not yet exist (had to debug the Infragistics code to figure this one).
  • Call endEdit which cancels the non-editable node from being edited.

Hope this helps!