2012-07-31 01:06:10 +06:00
using System ;
2012-07-27 05:52:01 +06:00
using System.Collections.Generic ;
2012-09-25 11:06:32 +07:00
using System.Linq ;
2012-07-27 05:52:01 +06:00
using System.Threading ;
2012-08-01 09:49:10 +06:00
using System.Web ;
2012-07-27 05:52:01 +06:00
2012-08-10 13:18:13 +06:00
namespace Umbraco.Core.ObjectResolution
2012-07-27 05:52:01 +06:00
{
2013-03-12 01:50:56 +04:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// The base class for all many-objects resolvers.
/// </summary>
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
/// <typeparam name="TResolved">The type of the resolved objects.</typeparam>
public abstract class ManyObjectsResolverBase < TResolver , TResolved > : ResolverBase < TResolver >
2013-03-12 01:50:56 +04:00
where TResolved : class
where TResolver : ResolverBase
2012-07-27 05:52:01 +06:00
{
2013-01-16 13:10:34 -01:00
private IEnumerable < TResolved > _applicationInstances = null ;
2012-08-01 09:49:10 +06:00
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim ( ) ;
2013-01-16 13:31:04 -01:00
private readonly string _httpContextKey ;
2013-02-13 03:29:32 +06:00
private readonly List < Type > _instanceTypes = new List < Type > ( ) ;
private IEnumerable < TResolved > _sortedValues = null ;
2013-01-23 07:45:00 +03:00
2013-01-16 13:10:34 -01:00
private int _defaultPluginWeight = 10 ;
2012-08-01 09:49:10 +06:00
#region Constructors
2013-01-16 13:10:34 -01:00
2012-08-01 09:49:10 +06:00
/// <summary>
2013-01-23 16:44:38 -01:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
/// and an optional lifetime scope.
2012-08-01 09:49:10 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( ObjectLifetimeScope scope = ObjectLifetimeScope . Application )
2012-08-01 09:49:10 +06:00
{
2012-08-14 12:03:34 +06:00
CanResolveBeforeFrozen = false ;
2012-08-01 10:48:19 +06:00
if ( scope = = ObjectLifetimeScope . HttpRequest )
{
if ( HttpContext . Current = = null )
throw new InvalidOperationException ( "Use alternative constructor accepting a HttpContextBase object in order to set the lifetime scope to HttpRequest when HttpContext.Current is null" ) ;
2013-01-16 13:10:34 -01:00
2012-08-01 10:48:19 +06:00
CurrentHttpContext = new HttpContextWrapper ( HttpContext . Current ) ;
}
LifetimeScope = scope ;
2013-01-16 13:31:04 -01:00
if ( scope = = ObjectLifetimeScope . HttpRequest )
_httpContextKey = this . GetType ( ) . FullName ;
2013-01-23 07:45:00 +03:00
_instanceTypes = new List < Type > ( ) ;
2012-08-01 09:49:10 +06:00
}
2012-07-27 05:52:01 +06:00
2012-07-27 14:06:41 -02:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
2012-08-01 09:49:10 +06:00
/// with creation of objects based on an HttpRequest lifetime scope.
2012-07-27 14:06:41 -02:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( HttpContextBase httpContext )
2012-07-27 05:52:01 +06:00
{
2012-08-14 12:03:34 +06:00
CanResolveBeforeFrozen = false ;
2013-01-16 13:10:34 -01:00
if ( httpContext = = null )
throw new ArgumentNullException ( "httpContext" ) ;
2012-08-01 10:48:19 +06:00
LifetimeScope = ObjectLifetimeScope . HttpRequest ;
2013-01-16 13:31:04 -01:00
_httpContextKey = this . GetType ( ) . FullName ;
2012-08-01 09:49:10 +06:00
CurrentHttpContext = httpContext ;
2013-01-23 07:45:00 +03:00
_instanceTypes = new List < Type > ( ) ;
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
2013-01-23 16:44:38 -01:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of object types,
/// and an optional lifetime scope.
2012-07-27 14:06:41 -02:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="value">The list of object types.</param>
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( IEnumerable < Type > value , ObjectLifetimeScope scope = ObjectLifetimeScope . Application )
2012-08-01 10:48:19 +06:00
: this ( scope )
2013-01-23 07:45:00 +03:00
{
2013-01-16 13:10:34 -01:00
_instanceTypes = value . ToList ( ) ;
2012-07-27 14:06:41 -02:00
}
2012-07-27 05:52:01 +06:00
2012-07-27 14:06:41 -02:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects,
2012-08-01 09:49:10 +06:00
/// with creation of objects based on an HttpRequest lifetime scope.
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
/// <param name="value">The list of object types.</param>
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
2012-08-01 11:24:39 +06:00
protected ManyObjectsResolverBase ( HttpContextBase httpContext , IEnumerable < Type > value )
2012-08-01 10:48:19 +06:00
: this ( httpContext )
2012-08-01 09:49:10 +06:00
{
2013-01-16 13:10:34 -01:00
_instanceTypes = value . ToList ( ) ;
2012-08-01 09:49:10 +06:00
}
#endregion
2012-08-14 12:03:34 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets or sets a value indicating whether the resolver can resolve objects before resolution is frozen.
2012-08-14 12:03:34 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <remarks>This is false by default and is used for some special internal resolvers.</remarks>
2012-08-14 12:03:34 +06:00
internal bool CanResolveBeforeFrozen { get ; set ; }
2012-08-01 09:49:10 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets the list of types to create instances from.
2012-08-01 09:49:10 +06:00
/// </summary>
2013-01-23 07:45:00 +03:00
protected virtual IEnumerable < Type > InstanceTypes
{
get { return _instanceTypes ; }
}
2012-08-01 09:49:10 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets or sets the <see cref="HttpContextBase"/> used to initialize this object, if any.
2012-08-01 09:49:10 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <remarks>If not null, then <c>LifetimeScope</c> will be <c>ObjectLifetimeScope.HttpRequest</c>.</remarks>
2012-08-01 09:49:10 +06:00
protected HttpContextBase CurrentHttpContext { get ; private set ; }
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets or sets the lifetime scope of resolved objects.
2012-08-01 09:49:10 +06:00
/// </summary>
2012-08-01 10:48:19 +06:00
protected ObjectLifetimeScope LifetimeScope { get ; private set ; }
2012-08-01 09:49:10 +06:00
2012-09-25 11:06:32 +07:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets the resolved object instances, sorted by weight.
/// </summary>
/// <returns>The sorted resolved object instances.</returns>
/// <remarks>
/// <para>The order is based upon the <c>WeightedPluginAttribute</c> and <c>DefaultPluginWeight</c>.</para>
/// <para>Weights are sorted ascendingly (lowest weights come first).</para>
/// </remarks>
protected IEnumerable < TResolved > GetSortedValues ( )
{
2013-02-13 03:29:32 +06:00
if ( _sortedValues = = null )
{
var values = Values . ToList ( ) ;
values . Sort ( ( f1 , f2 ) = > GetObjectWeight ( f1 ) . CompareTo ( GetObjectWeight ( f2 ) ) ) ;
_sortedValues = values ;
}
return _sortedValues ;
2013-01-16 13:10:34 -01:00
}
/// <summary>
/// Gets or sets the default type weight.
2012-09-25 11:06:32 +07:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <remarks>Determines the weight of types that do not have a <c>WeightedPluginAttribute</c> set on
/// them, when calling <c>GetSortedValues</c>.</remarks>
2012-09-25 11:06:32 +07:00
protected virtual int DefaultPluginWeight
{
get { return _defaultPluginWeight ; }
set { _defaultPluginWeight = value ; }
}
2013-02-13 03:29:32 +06:00
/// <summary>
/// Returns the weight of an object for user with GetSortedValues
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
protected virtual int GetObjectWeight ( object o )
2012-09-25 11:06:32 +07:00
{
2013-01-16 13:10:34 -01:00
var type = o . GetType ( ) ;
var attr = type . GetCustomAttribute < WeightedPluginAttribute > ( true ) ;
return attr = = null ? DefaultPluginWeight : attr . Weight ;
}
2012-09-25 11:06:32 +07:00
2012-08-01 09:49:10 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Gets the resolved object instances.
2012-07-27 14:06:41 -02:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <exception cref="InvalidOperationException"><c>CanResolveBeforeFrozen</c> is false, and resolution is not frozen.</exception>
2012-07-27 14:06:41 -02:00
protected IEnumerable < TResolved > Values
2012-07-27 05:52:01 +06:00
{
2012-08-01 09:49:10 +06:00
get
2013-01-16 13:31:04 -01:00
{
// ensure we can
2013-05-13 21:11:03 -10:00
if ( CanResolveBeforeFrozen = = false )
2013-01-16 13:31:04 -01:00
Resolution . EnsureIsFrozen ( ) ;
2013-01-16 13:10:34 -01:00
// note: we apply .ToArray() to the output of CreateInstance() because that is an IEnumerable that
// comes from the PluginManager we want to be _sure_ that it's not a Linq of some sort, but the
// instances have actually been instanciated when we return.
2012-08-01 22:06:15 +06:00
2012-08-01 09:49:10 +06:00
switch ( LifetimeScope )
{
case ObjectLifetimeScope . HttpRequest :
2013-01-16 13:10:34 -01:00
// create new instances per HttpContext
2012-08-01 09:49:10 +06:00
using ( var l = new UpgradeableReadLock ( _lock ) )
{
2013-01-16 13:10:34 -01:00
// create if not already there
2013-01-16 13:31:04 -01:00
if ( CurrentHttpContext . Items [ _httpContextKey ] = = null )
2012-08-01 09:49:10 +06:00
{
l . UpgradeToWriteLock ( ) ;
2013-01-16 13:31:04 -01:00
CurrentHttpContext . Items [ _httpContextKey ] = CreateInstances ( ) . ToArray ( ) ;
2012-08-01 09:49:10 +06:00
}
2013-01-23 09:41:01 -01:00
return ( TResolved [ ] ) CurrentHttpContext . Items [ _httpContextKey ] ;
2012-08-01 09:49:10 +06:00
}
2013-01-16 13:10:34 -01:00
2012-08-01 09:49:10 +06:00
case ObjectLifetimeScope . Application :
2013-01-16 13:10:34 -01:00
// create new instances per application
2012-08-01 09:49:10 +06:00
using ( var l = new UpgradeableReadLock ( _lock ) )
{
2013-01-16 13:10:34 -01:00
// create if not already there
2012-08-01 09:49:10 +06:00
if ( _applicationInstances = = null )
{
l . UpgradeToWriteLock ( ) ;
2013-01-16 13:10:34 -01:00
_applicationInstances = CreateInstances ( ) . ToArray ( ) ;
2012-08-01 09:49:10 +06:00
}
return _applicationInstances ;
}
2013-01-16 13:10:34 -01:00
2012-08-01 09:49:10 +06:00
case ObjectLifetimeScope . Transient :
default :
2013-01-16 13:10:34 -01:00
// create new instances each time
return CreateInstances ( ) . ToArray ( ) ;
2012-08-01 09:49:10 +06:00
}
}
2012-07-27 05:52:01 +06:00
}
2013-01-16 13:10:34 -01:00
/// <summary>
/// Creates the object instances for the types contained in the types collection.
/// </summary>
/// <returns>A list of objects of type <typeparamref name="TResolved"/>.</returns>
2012-08-01 23:30:37 +06:00
protected virtual IEnumerable < TResolved > CreateInstances ( )
{
return PluginManager . Current . CreateInstances < TResolved > ( InstanceTypes ) ;
2013-01-16 13:10:34 -01:00
}
2013-01-16 13:31:04 -01:00
#region Types collection manipulation
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 09:49:10 +06:00
/// Removes a type.
2012-07-27 14:06:41 -02:00
/// </summary>
2012-08-01 09:49:10 +06:00
/// <param name="value">The type to remove.</param>
2013-01-16 13:10:34 -01:00
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
/// the type is not a valid type for the resolver.</exception>
2013-01-23 07:45:00 +03:00
public virtual void RemoveType ( Type value )
2012-10-13 10:59:21 +05:00
{
2013-01-23 16:44:38 -01:00
EnsureSupportsRemove ( ) ;
2013-01-23 07:45:00 +03:00
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
2013-01-16 13:10:34 -01:00
using ( var l = new UpgradeableReadLock ( _lock ) )
2012-08-01 09:49:10 +06:00
{
2012-10-13 10:59:21 +05:00
EnsureCorrectType ( value ) ;
2013-01-16 13:10:34 -01:00
l . UpgradeToWriteLock ( ) ;
2013-01-23 07:45:00 +03:00
_instanceTypes . Remove ( value ) ;
2012-07-27 05:52:01 +06:00
}
}
2012-07-27 14:06:41 -02:00
/// <summary>
2012-08-01 09:49:10 +06:00
/// Removes a type.
/// </summary>
2013-01-16 13:10:34 -01:00
/// <typeparam name="T">The type to remove.</typeparam>
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
/// the type is not a valid type for the resolver.</exception>
2012-08-01 10:48:19 +06:00
public void RemoveType < T > ( )
2013-01-23 09:41:01 -01:00
where T : TResolved
2012-08-01 09:49:10 +06:00
{
2013-01-16 13:10:34 -01:00
RemoveType ( typeof ( T ) ) ;
2012-08-01 09:49:10 +06:00
}
2012-10-13 10:59:21 +05:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Adds types.
2012-10-13 10:59:21 +05:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="types">The types to add.</param>
/// <remarks>The types are appended at the end of the list.</remarks>
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
/// a type is not a valid type for the resolver, or a type is already in the collection of types.</exception>
2012-10-13 10:59:21 +05:00
protected void AddTypes ( IEnumerable < Type > types )
2013-01-23 07:45:00 +03:00
{
2013-01-23 16:44:38 -01:00
EnsureSupportsAdd ( ) ;
2013-01-23 07:45:00 +03:00
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
2013-01-16 13:10:34 -01:00
using ( new WriteLock ( _lock ) )
2012-10-13 10:59:21 +05:00
{
foreach ( var t in types )
{
EnsureCorrectType ( t ) ;
2013-01-23 16:44:38 -01:00
if ( _instanceTypes . Contains ( t ) )
2012-10-13 10:59:21 +05:00
{
2013-01-16 13:10:34 -01:00
throw new InvalidOperationException ( string . Format (
"Type {0} is already in the collection of types." , t . FullName ) ) ;
}
2013-01-23 07:45:00 +03:00
_instanceTypes . Add ( t ) ;
2012-10-13 10:59:21 +05:00
}
}
}
2012-08-01 09:49:10 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Adds a type.
2012-07-27 14:06:41 -02:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="value">The type to add.</param>
/// <remarks>The type is appended at the end of the list.</remarks>
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
2013-01-23 07:45:00 +03:00
public virtual void AddType ( Type value )
2012-07-27 05:52:01 +06:00
{
2013-01-23 16:44:38 -01:00
EnsureSupportsAdd ( ) ;
2012-10-13 10:59:21 +05:00
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
2013-01-16 13:10:34 -01:00
using ( var l = new UpgradeableReadLock ( _lock ) )
2012-07-27 05:52:01 +06:00
{
2012-10-13 10:59:21 +05:00
EnsureCorrectType ( value ) ;
2013-01-23 16:44:38 -01:00
if ( _instanceTypes . Contains ( value ) )
2012-07-31 01:06:10 +06:00
{
2013-01-16 13:10:34 -01:00
throw new InvalidOperationException ( string . Format (
"Type {0} is already in the collection of types." , value . FullName ) ) ;
}
l . UpgradeToWriteLock ( ) ;
2013-01-23 07:45:00 +03:00
_instanceTypes . Add ( value ) ;
2012-07-27 06:02:41 +06:00
}
2012-07-27 05:52:01 +06:00
}
2012-08-01 09:49:10 +06:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Adds a type.
2012-08-01 09:49:10 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <typeparam name="T">The type to add.</typeparam>
/// <remarks>The type is appended at the end of the list.</remarks>
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
2012-08-01 10:48:19 +06:00
public void AddType < T > ( )
2013-01-23 09:41:01 -01:00
where T : TResolved
2012-08-01 09:49:10 +06:00
{
2013-01-16 13:10:34 -01:00
AddType ( typeof ( T ) ) ;
2012-08-01 09:49:10 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Clears the list of types.
2012-07-27 14:06:41 -02:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <exception cref="InvalidOperationException">the resolver does not support clearing types.</exception>
2013-01-23 07:45:00 +03:00
public virtual void Clear ( )
2012-07-27 05:52:01 +06:00
{
2013-01-23 16:44:38 -01:00
EnsureSupportsClear ( ) ;
2013-01-23 07:45:00 +03:00
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
2013-01-16 13:10:34 -01:00
using ( new WriteLock ( _lock ) )
2012-07-27 05:52:01 +06:00
{
2013-01-23 07:45:00 +03:00
_instanceTypes . Clear ( ) ;
2012-07-27 06:02:41 +06:00
}
2012-07-27 05:52:01 +06:00
}
2012-07-27 14:06:41 -02:00
/// <summary>
2013-01-16 13:10:34 -01:00
/// Inserts a type at the specified index.
2012-07-27 14:06:41 -02:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <param name="index">The zero-based index at which the type should be inserted.</param>
/// <param name="value">The type to insert.</param>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
2013-01-23 07:45:00 +03:00
public virtual void InsertType ( int index , Type value )
2012-10-13 10:59:21 +05:00
{
2013-01-23 16:44:38 -01:00
EnsureSupportsInsert ( ) ;
2012-10-13 10:59:21 +05:00
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
2013-01-16 13:10:34 -01:00
using ( var l = new UpgradeableReadLock ( _lock ) )
2012-07-27 05:52:01 +06:00
{
2012-10-13 10:59:21 +05:00
EnsureCorrectType ( value ) ;
2013-01-23 16:44:38 -01:00
if ( _instanceTypes . Contains ( value ) )
2012-07-31 01:06:10 +06:00
{
2013-01-16 13:10:34 -01:00
throw new InvalidOperationException ( string . Format (
"Type {0} is already in the collection of types." , value . FullName ) ) ;
}
2012-07-31 01:06:10 +06:00
2013-01-16 13:10:34 -01:00
l . UpgradeToWriteLock ( ) ;
2013-01-23 07:45:00 +03:00
_instanceTypes . Insert ( index , value ) ;
2012-07-27 06:02:41 +06:00
}
2012-07-27 05:52:01 +06:00
}
2012-08-01 09:49:10 +06:00
2013-01-30 14:45:08 -01:00
/// <summary>
/// Inserts a type at the beginning of the list.
/// </summary>
/// <param name="value">The type to insert.</param>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
public virtual void InsertType ( Type value )
{
InsertType ( 0 , value ) ;
}
/// <summary>
2013-01-16 13:10:34 -01:00
/// Inserts a type at the specified index.
2012-08-01 09:49:10 +06:00
/// </summary>
2013-01-16 13:10:34 -01:00
/// <typeparam name="T">The type to insert.</typeparam>
/// <param name="index">The zero-based index at which the type should be inserted.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
2012-08-01 10:48:19 +06:00
public void InsertType < T > ( int index )
2013-01-23 09:41:01 -01:00
where T : TResolved
2012-08-01 09:49:10 +06:00
{
2013-01-16 13:10:34 -01:00
InsertType ( index , typeof ( T ) ) ;
}
2013-01-30 14:45:08 -01:00
/// <summary>
/// Inserts a type at the beginning of the list.
/// </summary>
/// <typeparam name="T">The type to insert.</typeparam>
public void InsertType < T > ( )
where T : TResolved
{
InsertType ( 0 , typeof ( T ) ) ;
}
/// <summary>
2013-01-16 13:10:34 -01:00
/// Inserts a type before a specified, already existing type.
/// </summary>
/// <param name="existingType">The existing type before which to insert.</param>
/// <param name="value">The type to insert.</param>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
/// or the new type is already in the collection of types.</exception>
public virtual void InsertTypeBefore ( Type existingType , Type value )
{
2013-01-23 16:44:38 -01:00
EnsureSupportsInsert ( ) ;
2013-01-16 13:10:34 -01:00
2013-01-16 13:31:04 -01:00
using ( Resolution . Configuration )
2013-01-16 13:10:34 -01:00
using ( var l = new UpgradeableReadLock ( _lock ) )
{
EnsureCorrectType ( existingType ) ;
EnsureCorrectType ( value ) ;
2013-01-23 16:44:38 -01:00
if ( ! _instanceTypes . Contains ( existingType ) )
2013-01-16 13:10:34 -01:00
{
throw new InvalidOperationException ( string . Format (
"Type {0} is not in the collection of types." , existingType . FullName ) ) ;
}
2013-01-23 16:44:38 -01:00
if ( _instanceTypes . Contains ( value ) )
2013-01-16 13:10:34 -01:00
{
throw new InvalidOperationException ( string . Format (
"Type {0} is already in the collection of types." , value . FullName ) ) ;
}
2013-01-23 16:44:38 -01:00
int index = _instanceTypes . IndexOf ( existingType ) ;
2013-01-16 13:10:34 -01:00
l . UpgradeToWriteLock ( ) ;
_instanceTypes . Insert ( index , value ) ;
}
2012-08-01 09:49:10 +06:00
}
2013-01-16 13:10:34 -01:00
/// <summary>
/// Inserts a type before a specified, already existing type.
/// </summary>
2013-02-13 03:29:32 +06:00
/// <typeparam name="TExisting">The existing type before which to insert.</typeparam>
2013-01-16 13:10:34 -01:00
/// <typeparam name="T">The type to insert.</typeparam>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
/// or the new type is already in the collection of types.</exception>
2013-02-13 03:29:32 +06:00
public void InsertTypeBefore < TExisting , T > ( )
where TExisting : TResolved
2013-01-23 09:41:01 -01:00
where T : TResolved
2013-01-16 13:10:34 -01:00
{
2013-02-13 03:29:32 +06:00
InsertTypeBefore ( typeof ( TExisting ) , typeof ( T ) ) ;
2013-01-16 13:10:34 -01:00
}
/// <summary>
/// Returns a value indicating whether the specified type is already in the collection of types.
/// </summary>
/// <param name="value">The type to look for.</param>
/// <returns>A value indicating whether the type is already in the collection of types.</returns>
public virtual bool ContainsType ( Type value )
{
using ( new ReadLock ( _lock ) )
{
return _instanceTypes . Contains ( value ) ;
}
}
/// <summary>
/// Returns a value indicating whether the specified type is already in the collection of types.
/// </summary>
/// <typeparam name="T">The type to look for.</typeparam>
/// <returns>A value indicating whether the type is already in the collection of types.</returns>
public bool ContainsType < T > ( )
2013-01-23 09:41:01 -01:00
where T : TResolved
2013-01-16 13:10:34 -01:00
{
return ContainsType ( typeof ( T ) ) ;
}
#endregion
2013-01-23 07:45:00 +03:00
/// <summary>
/// Returns a WriteLock to use when modifying collections
/// </summary>
/// <returns></returns>
protected WriteLock GetWriteLock ( )
{
return new WriteLock ( _lock ) ;
}
2013-01-23 16:44:38 -01:00
#region Type utilities
/// <summary>
/// Ensures that a type is a valid type for the resolver.
/// </summary>
/// <param name="value">The type to test.</param>
/// <exception cref="InvalidOperationException">the type is not a valid type for the resolver.</exception>
2013-08-29 17:14:34 +10:00
protected virtual void EnsureCorrectType ( Type value )
2013-01-23 16:44:38 -01:00
{
if ( ! TypeHelper . IsTypeAssignableFrom < TResolved > ( value ) )
throw new InvalidOperationException ( string . Format (
"Type {0} is not an acceptable type for resolver {1}." , value . FullName , this . GetType ( ) . FullName ) ) ;
}
#endregion
#region Types collection manipulation support
/// <summary>
/// Ensures that the resolver supports removing types.
/// </summary>
/// <exception cref="InvalidOperationException">The resolver does not support removing types.</exception>
protected void EnsureSupportsRemove ( )
2013-01-23 07:45:00 +03:00
{
if ( ! SupportsRemove )
2013-01-23 16:44:38 -01:00
throw new InvalidOperationException ( "This resolver does not support removing types" ) ;
2013-01-23 07:45:00 +03:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Ensures that the resolver supports clearing types.
/// </summary>
/// <exception cref="InvalidOperationException">The resolver does not support clearing types.</exception>
protected void EnsureSupportsClear ( ) {
2013-01-23 07:45:00 +03:00
if ( ! SupportsClear )
2013-01-23 16:44:38 -01:00
throw new InvalidOperationException ( "This resolver does not support clearing types" ) ;
2013-01-23 07:45:00 +03:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Ensures that the resolver supports adding types.
/// </summary>
/// <exception cref="InvalidOperationException">The resolver does not support adding types.</exception>
protected void EnsureSupportsAdd ( )
2013-01-23 07:45:00 +03:00
{
if ( ! SupportsAdd )
2013-01-23 16:44:38 -01:00
throw new InvalidOperationException ( "This resolver does not support adding new types" ) ;
2013-01-23 07:45:00 +03:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Ensures that the resolver supports inserting types.
/// </summary>
/// <exception cref="InvalidOperationException">The resolver does not support inserting types.</exception>
protected void EnsureSupportsInsert ( )
2013-01-23 07:45:00 +03:00
{
if ( ! SupportsInsert )
2013-01-23 16:44:38 -01:00
throw new InvalidOperationException ( "This resolver does not support inserting new types" ) ;
2013-01-23 07:45:00 +03:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Gets a value indicating whether the resolver supports adding types.
/// </summary>
2012-10-13 10:59:21 +05:00
protected virtual bool SupportsAdd
{
2013-01-23 07:45:00 +03:00
get { return true ; }
2012-10-13 10:59:21 +05:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Gets a value indicating whether the resolver supports inserting types.
/// </summary>
protected virtual bool SupportsInsert
2012-10-13 10:59:21 +05:00
{
2013-01-23 07:45:00 +03:00
get { return true ; }
2012-10-13 10:59:21 +05:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Gets a value indicating whether the resolver supports clearing types.
/// </summary>
protected virtual bool SupportsClear
2012-10-13 10:59:21 +05:00
{
2013-01-23 07:45:00 +03:00
get { return true ; }
2012-10-13 10:59:21 +05:00
}
2013-01-23 16:44:38 -01:00
/// <summary>
/// Gets a value indicating whether the resolver supports removing types.
/// </summary>
protected virtual bool SupportsRemove
2012-10-13 10:59:21 +05:00
{
2013-01-23 07:45:00 +03:00
get { return true ; }
2013-01-23 16:44:38 -01:00
}
#endregion
}
2012-07-27 05:52:01 +06:00
}