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. protected 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; } } } }