2012-07-26 07:52:13 -02:00
using System ;
2013-01-16 13:31:04 -01:00
using System.Threading ;
2012-07-26 07:52:13 -02:00
2012-08-10 13:18:13 +06:00
namespace Umbraco.Core.ObjectResolution
2012-07-26 07:52:13 -02:00
{
2012-07-27 05:52:01 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// The base class for all single-object resolvers.
2012-07-27 05:52:01 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
/// <typeparam name="TResolved">The type of the resolved object.</typeparam>
2012-07-27 05:52:01 +06:00
/// <remarks>
2013-01-16 13:10:34 -01:00
/// Resolves "single" objects ie objects for which there is only one application-wide instance, such as the MVC Controller factory.
2012-07-27 05:52:01 +06:00
/// </remarks>
2013-01-16 13:10:34 -01:00
public abstract class SingleObjectResolverBase < TResolver , TResolved > : ResolverBase < TResolver >
2012-07-27 05:25:26 +06:00
where TResolved : class
2012-08-01 22:06:15 +06:00
where TResolver : class
2012-07-26 07:52:13 -02:00
{
2013-01-16 13:31:04 -01:00
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim ( ) ;
private readonly bool _canBeNull ;
private TResolved _value ;
2013-01-16 13:10:34 -01:00
#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>
2012-07-30 22:52:59 +06:00
protected SingleObjectResolverBase ( )
2012-07-26 07:52:13 -02:00
: this ( false )
{ }
2013-01-16 13:10:34 -01:00
/// <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>
2012-07-30 22:52:59 +06:00
protected SingleObjectResolverBase ( TResolved value )
2012-07-26 07:52:13 -02:00
: this ( false )
{
2013-01-16 13:31:04 -01:00
_value = value ;
2012-07-26 07:52:13 -02:00
}
2013-01-16 13:10:34 -01:00
/// <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>
2012-07-30 22:52:59 +06:00
protected SingleObjectResolverBase ( bool canBeNull )
2012-07-26 07:52:13 -02:00
{
_canBeNull = canBeNull ;
}
2013-01-16 13:10:34 -01:00
/// <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>
2012-07-30 22:52:59 +06:00
protected SingleObjectResolverBase ( TResolved value , bool canBeNull )
2012-07-26 07:52:13 -02:00
{
2013-01-16 13:31:04 -01:00
_value = value ;
2012-07-26 07:52:13 -02:00
_canBeNull = canBeNull ;
}
2013-01-16 13:10:34 -01:00
#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
{
2013-01-16 13:31:04 -01:00
get { return _value ! = null ; }
2013-01-16 13:10:34 -01:00
}
2012-07-27 05:52:01 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets or sets the resolved object instance.
2012-07-27 05:52:01 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <remarks></remarks>
/// <exception cref="ArgumentNullException">value is set to null, but cannot be null (<c>CanBeNull</c> is <c>false</c>).</exception>
2013-01-16 13:31:04 -01:00
/// <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>
2012-07-26 07:52:13 -02:00
protected TResolved Value
{
get
{
2013-01-16 13:31:04 -01:00
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 ;
}
2012-07-26 07:52:13 -02:00
}
set
{
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
using ( var l = new UpgradeableReadLock ( _lock ) )
{
if ( ! _canBeNull & & value = = null )
throw new ArgumentNullException ( "value" ) ;
l . UpgradeToWriteLock ( ) ;
_value = value ;
}
2012-07-26 07:52:13 -02:00
}
}
}
}