SingleInstance(Of T) Class for Windows Phone 7





0/5 (0 vote)
This post aims to provide a way to implement lazy initialization in a multi threaded environment using the SingleInstance(Of T) Class.
When building applications for a mobile operating system such as Windows Phone 7 (WP7), you might want (at times) to defer the creation of large objects, specifically when this creation is going to increase memory consumption. While in the desktop CLR there is the Lazy(Of T) Class, when working on WP7, this class does not exist (at least not at the time of this writing).
I find it a very repetitive task to manually produce a single instance object:
- Make its constructor private.
- Write the code for initialization.
- Provide a getter method that returns the one and only instance.
While you cannot avoid step 2, it is possible to create a generic class that produces step 1 and step 3. Then, from the class constructor, you can pass the code that creates the object using a Func(TResult) Delegate.
Update: The first version of the
SingleInstance(Of T)
class provided an option to create an instance(Of T)
using the thread pool. This option is removed in the current version.
SingleInstance(Of T) Class
using System;
using System.Threading;
public sealed class SingleInstance<T> where T : class
{
private readonly Object m_lockObj = new Object();
private readonly Func<T> m_delegate;
private Boolean m_isDelegateInvoked;
private T m_value;
/// <summary>
/// Initializes a new instance of the
/// <see cref="SingleInstance<T>"/> class.
/// </summary>
public SingleInstance()
: this(() => default(T)) { }
/// <summary>
/// Initializes a new instance of the
/// <see cref="SingleInstance<T>"/> class.
/// </summary>
/// <param name="delegate">The @delegate.</param>
public SingleInstance(Func<T> @delegate)
{
m_delegate = @delegate;
}
/// <summary>
/// Gets the instance.
/// </summary>
/// <value>The instance.</value>
public T Instance
{
get
{
if (!m_isDelegateInvoked)
{
T temp = m_delegate();
Interlocked.CompareExchange<T>(ref m_value, temp, null);
Boolean lockTaken = false;
try
{
// WP7 does not support the overload with the
// Boolean indicating if the lock was taken.
Monitor.Enter(m_lockObj); lockTaken = true;
m_isDelegateInvoked = true;
}
finally
{
if (lockTaken) { Monitor.Exit(m_lockObj); }
}
}
return m_value;
}
}
}
The SingleInstance(Of T)
class has many differences from the System.Lazy(Of T)
class in the desktop CLR.
- The
System.Lazy(Of T)
class takes a LazyThreadSafetyMode enumeration. This enumeration contains 3 members (None
,PublicationOnly
,ExecutionAndPublication
). TheSingleInstance(Of T)
class uses the interlocked constructs to produce a single instance. This is similar with passingLazyThreadSafetyMode.ExecutionAndPublication
in theSystem.Lazy(Of T)
class. - The
System.Lazy(Of T)
class works with classes (reference types) and structs (value types). The value types are boxed internally. TheSingleInstance(Of T)
class works only with reference types. - Finally, the
System.Lazy(Of T)
class is written, tested and supported by Microsoft, while theSingleInstance(Of T)
is not.
Keep in mind that the SingleInstance(Of T)
class uses a Func(TResult)
delegate. There is a known performance hit when calling delegates compared to direct method calls. (See the Delegates section here.)