using System;
using System.Threading;
namespace Umbraco.Core.ObjectResolution
{
///
/// Base non-generic class for resolvers
///
public abstract class ResolverBase
{
protected ResolverBase(Action resetAction)
{
//add itself to the internal collection
ResolverCollection.Add(this, resetAction);
}
}
///
/// The base class for all resolvers.
///
/// The type of the concrete resolver class.
/// Provides singleton management to all resolvers.
public abstract class ResolverBase : ResolverBase
where TResolver : ResolverBase
{
///
/// The underlying singleton object instance
///
static TResolver _resolver;
///
/// The lock for the singleton.
///
///
/// 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
///
static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim();
///
/// Constructor set the reset action for the underlying object
///
protected ResolverBase()
: base(() => Reset())
{
}
///
/// Gets or sets the resolver singleton instance.
///
/// The value can be set only once, and cannot be read before it has been set.
/// value is read before it has been set, or value is set again once it has already been set.
/// value is null.
public static TResolver Current
{
get
{
using (new ReadLock(ResolversLock))
{
if (_resolver == null)
throw new InvalidOperationException(string.Format(
"Current has not been initialized on {0}. You must initialize Current before trying to read it.",
typeof(TResolver).FullName));
return _resolver;
}
}
set
{
using (Resolution.Configuration)
using (new WriteLock(ResolversLock))
{
if (value == null)
throw new ArgumentNullException("value");
if (_resolver != null)
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));
_resolver = value;
}
}
}
///
/// Gets a value indicating whether a the singleton nstance has been set.
///
/// To be used in unit tests.
internal static bool HasCurrent
{
get
{
using (new ReadLock(ResolversLock))
{
return _resolver != null;
}
}
}
///
/// Resets the resolver singleton instance to null.
///
/// To be used in unit tests.
/// 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.
internal static void Reset(bool resetResolution = true)
{
//In order to reset a resolver, we always must reset the resolution
if (resetResolution)
{
Resolution.Reset();
}
//ensure its removed from the collection
ResolverCollection.Remove(_resolver);
using (Resolution.Configuration)
using (new WriteLock(ResolversLock))
{
_resolver = null;
}
}
}
}