resolution and created a ResolverCollection to track all resolvers created so it's super easy to reset all of them at once (which is what happens on ApplicationContext.Dispose. ApplicationContext.Dispose is also implicitly implemented as to not show in intellisense that the Dispose method exists... must be cast to IDisposable to work.
125 lines
4.5 KiB
C#
125 lines
4.5 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
namespace Umbraco.Core.ObjectResolution
|
|
{
|
|
/// <summary>
|
|
/// The base class for all single-object resolvers.
|
|
/// </summary>
|
|
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
|
/// <typeparam name="TResolved">The type of the resolved object.</typeparam>
|
|
/// <remarks>
|
|
/// Resolves "single" objects ie objects for which there is only one application-wide instance, such as the MVC Controller factory.
|
|
/// </remarks>
|
|
public abstract class SingleObjectResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
|
where TResolved : class
|
|
where TResolver : ResolverBase
|
|
{
|
|
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
|
private readonly bool _canBeNull;
|
|
private TResolved _value;
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class.
|
|
/// </summary>
|
|
/// <remarks>By default <c>CanBeNull</c> is false, so <c>Value</c> has to be initialized before being read,
|
|
/// otherwise an exception will be thrown when reading it.</remarks>
|
|
protected SingleObjectResolverBase()
|
|
: this(false)
|
|
{ }
|
|
|
|
/// <summary>
|
|
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class with an instance of the resolved object.
|
|
/// </summary>
|
|
/// <param name="value">An instance of the resolved object.</param>
|
|
/// <remarks>By default <c>CanBeNull</c> is false, so <c>value</c> has to be non-null, or <c>Value</c> has to be
|
|
/// initialized before being accessed, otherwise an exception will be thrown when reading it.</remarks>
|
|
protected SingleObjectResolverBase(TResolved value)
|
|
: this(false)
|
|
{
|
|
_value = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class with a value indicating whether the resolved object instance can be null.
|
|
/// </summary>
|
|
/// <param name="canBeNull">A value indicating whether the resolved object instance can be null.</param>
|
|
/// <remarks>If <c>CanBeNull</c> is false, <c>Value</c> has to be initialized before being read,
|
|
/// otherwise an exception will be thrown when reading it.</remarks>
|
|
protected SingleObjectResolverBase(bool canBeNull)
|
|
{
|
|
_canBeNull = canBeNull;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class with an instance of the resolved object,
|
|
/// and a value indicating whether that instance can be null.
|
|
/// </summary>
|
|
/// <param name="value">An instance of the resolved object.</param>
|
|
/// <param name="canBeNull">A value indicating whether the resolved object instance can be null.</param>
|
|
/// <remarks>If <c>CanBeNull</c> is false, <c>value</c> has to be non-null, or <c>Value</c> has to be initialized before being read,
|
|
/// otherwise an exception will be thrown when reading it.</remarks>
|
|
protected SingleObjectResolverBase(TResolved value, bool canBeNull)
|
|
{
|
|
_value = value;
|
|
_canBeNull = canBeNull;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the resolved object instance can be null.
|
|
/// </summary>
|
|
public bool CanBeNull
|
|
{
|
|
get { return _canBeNull; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the resolved object instance is null.
|
|
/// </summary>
|
|
public bool HasValue
|
|
{
|
|
get { return _value != null; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the resolved object instance.
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
/// <exception cref="ArgumentNullException">value is set to null, but cannot be null (<c>CanBeNull</c> is <c>false</c>).</exception>
|
|
/// <exception cref="InvalidOperationException">value is read and is null, but cannot be null (<c>CanBeNull</c> is <c>false</c>),
|
|
/// or value is set (read) and resolution is (not) frozen.</exception>
|
|
protected TResolved Value
|
|
{
|
|
get
|
|
{
|
|
Resolution.EnsureIsFrozen();
|
|
using (new ReadLock(_lock))
|
|
{
|
|
if (!_canBeNull && _value == null)
|
|
throw new InvalidOperationException(string.Format(
|
|
"Resolver {0} requires a value, and none was supplied.", this.GetType().FullName));
|
|
|
|
return _value;
|
|
}
|
|
}
|
|
|
|
set
|
|
{
|
|
using (Resolution.Configuration)
|
|
using (var l = new UpgradeableReadLock(_lock))
|
|
{
|
|
if (!_canBeNull && value == null)
|
|
throw new ArgumentNullException("value");
|
|
|
|
l.UpgradeToWriteLock();
|
|
_value = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|