2012-08-01 22:06:15 +06:00
using System ;
using System.Threading ;
2012-08-10 13:18:13 +06:00
namespace Umbraco.Core.ObjectResolution
2012-08-01 22:06:15 +06:00
{
2013-03-12 01:50:56 +04:00
/// <summary>
/// Base non-generic class for resolvers
/// </summary>
public abstract class ResolverBase
{
protected ResolverBase ( Action resetAction )
{
//add itself to the internal collection
ResolverCollection . Add ( this , resetAction ) ;
}
2013-05-13 21:11:03 -10:00
2013-03-12 01:50:56 +04:00
}
2012-08-01 22:06:15 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// The base class for all resolvers.
2012-08-01 22:06:15 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
/// <remarks>Provides singleton management to all resolvers.</remarks>
2013-03-12 01:50:56 +04:00
public abstract class ResolverBase < TResolver > : ResolverBase
where TResolver : ResolverBase
2012-08-01 22:06:15 +06:00
{
2013-03-12 01:50:56 +04:00
/// <summary>
/// The underlying singleton object instance
/// </summary>
static TResolver _resolver ;
/// <summary>
/// The lock for the singleton.
/// </summary>
/// <remarks>
/// Though resharper says this is in error, it is actually correct. We want a different lock object for each generic type.
/// See this for details: http://confluence.jetbrains.net/display/ReSharper/Static+field+in+generic+type
/// </remarks>
static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim ( ) ;
/// <summary>
/// Constructor set the reset action for the underlying object
/// </summary>
protected ResolverBase ( )
: base ( ( ) = > Reset ( ) )
{
}
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets or sets the resolver singleton instance.
/// </summary>
/// <remarks>The value can be set only once, and cannot be read before it has been set.</remarks>
/// <exception cref="InvalidOperationException">value is read before it has been set, or value is set again once it has already been set.</exception>
/// <exception cref="ArgumentNullException">value is <c>null</c>.</exception>
2012-08-01 22:06:15 +06:00
public static TResolver Current
{
get
{
using ( new ReadLock ( ResolversLock ) )
{
if ( _resolver = = null )
2013-01-16 13:10:34 -01:00
throw new InvalidOperationException ( string . Format (
"Current has not been initialized on {0}. You must initialize Current before trying to read it." ,
typeof ( TResolver ) . FullName ) ) ;
2012-08-01 22:06:15 +06:00
return _resolver ;
}
}
set
{
2013-01-23 09:41:01 -01:00
using ( Resolution . Configuration )
2012-08-01 22:06:15 +06:00
using ( new WriteLock ( ResolversLock ) )
{
if ( value = = null )
throw new ArgumentNullException ( "value" ) ;
if ( _resolver ! = null )
2013-01-16 13:10:34 -01:00
throw new InvalidOperationException ( string . Format (
"Current has already been initialized on {0}. It is not possible to re-initialize Current once it has been initialized." ,
typeof ( TResolver ) . FullName ) ) ;
2012-08-01 22:06:15 +06:00
_resolver = value ;
}
}
}
2012-08-01 22:46:13 +06:00
2013-01-23 09:41:01 -01:00
/// <summary>
/// Gets a value indicating whether a the singleton nstance has been set.
/// </summary>
/// <remarks>To be used in unit tests.</remarks>
internal static bool HasCurrent
{
get
{
using ( new ReadLock ( ResolversLock ) )
{
return _resolver ! = null ;
}
}
}
2012-08-01 22:46:13 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Resets the resolver singleton instance to null.
2012-08-01 22:46:13 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <remarks>To be used in unit tests.</remarks>
2013-02-05 03:10:01 +06:00
/// <param name="resetResolution">By default this is true because we always need to reset resolution before we reset a resolver, however in some insanely rare cases like unit testing you might not want to do this.</param>
internal static void Reset ( bool resetResolution = true )
2012-08-01 22:46:13 +06:00
{
2013-02-05 03:10:01 +06:00
//In order to reset a resolver, we always must reset the resolution
if ( resetResolution )
{
2013-03-12 01:50:56 +04:00
Resolution . Reset ( ) ;
2013-02-05 03:10:01 +06:00
}
2013-03-12 01:50:56 +04:00
//ensure its removed from the collection
ResolverCollection . Remove ( _resolver ) ;
2013-02-05 03:10:01 +06:00
2013-01-23 09:41:01 -01:00
using ( Resolution . Configuration )
2013-01-16 13:31:04 -01:00
using ( new WriteLock ( ResolversLock ) )
{
_resolver = null ;
}
2013-03-12 01:50:56 +04:00
2012-08-01 22:46:13 +06:00
}
2012-08-01 22:06:15 +06:00
}
}