using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Umbraco.Core.ObjectResolution
{
///
/// A base class for lazily resolving types for a resolver
///
///
///
///
/// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
/// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
/// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances.
///
/// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless
/// the types are marked with the WeightedPluginAttribute.
///
internal abstract class LazyManyObjectsResolverBase : ManyObjectsResolverBase
where TResolved : class
where TResolver : class
{
#region Constructors
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: base(scope)
{
}
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
: base(httpContext)
{
}
///
/// Constructor accepting a list of lazy types
///
///
///
protected LazyManyObjectsResolverBase(IEnumerable> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
AddTypes(listOfLazyTypes);
}
///
/// Constructor accepting a delegate to return a list of types
///
///
///
protected LazyManyObjectsResolverBase(Func> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
///
/// Constructor accepting a list of lazy types
///
///
///
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable> listOfLazyTypes)
: this(httpContext)
{
AddTypes(listOfLazyTypes);
}
///
/// Constructor accepting a delegate to return a list of types
///
///
///
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func> typeListDelegate)
: this(httpContext)
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
#endregion
private readonly List> _lazyTypeList = new List>();
private readonly List>> _listOfTypeListDelegates = new List>>();
private List _resolvedTypes = null;
///
/// Used for unit tests
///
internal bool HasResolvedTypes
{
get { return _resolvedTypes != null; }
}
///
/// Once this is called this will resolve all types registered in the lazy list
///
protected override IEnumerable InstanceTypes
{
get
{
using (var lck = GetUpgradeableReadLock())
{
var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
//we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
if (!HasResolvedTypes)
{
lck.UpgradeToWriteLock();
_resolvedTypes = new List();
//first iterate the lazy type list
foreach (var l in lazyTypeList)
{
UpdateUniqueList(_resolvedTypes, l);
}
//next iterate the list of list type delegates
foreach (var l in listofTypeListDelegates)
{
UpdateUniqueList(_resolvedTypes, l);
}
}
return _resolvedTypes;
}
}
}
private void UpdateUniqueList(List uniqueList, Type toAdd)
{
EnsureCorrectType(toAdd);
if (uniqueList.Contains(toAdd))
{
throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
}
uniqueList.Add(toAdd);
}
///
/// Allows adding of multiple lazy types at once
///
///
protected void AddTypes(IEnumerable> types)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
foreach (var t in types)
{
_lazyTypeList.Add(t);
}
}
}
///
/// Adds a type list delegate to the collection
///
///
public void AddTypeListDelegate(Func> typeListDelegate)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
}
///
/// Adds a lazy type to the list
///
///
public void AddType(Lazy value)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_lazyTypeList.Add(value);
}
}
///
/// Converts the static type added to a lazy type and adds it to the internal list
///
///
public override void AddType(Type value)
{
AddType(new Lazy(() => value));
}
///
/// Clears all lazy types
///
public override void Clear()
{
EnsureClearSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_lazyTypeList.Clear();
}
}
///
/// Does not support removal
///
protected override bool SupportsRemove
{
get { return false; }
}
///
/// Does not support insert
///
protected override bool SupportsInsert
{
get { return false; }
}
}
}