Adds more functionality for LazyManyObjectsResolverBase - adding type list delegates for lazy resolution.

This commit is contained in:
Shannon Deminick
2013-01-23 17:39:07 +03:00
parent aea1a03453
commit f467b8cb6c
3 changed files with 181 additions and 28 deletions

View File

@@ -5,6 +5,19 @@ using System.Web;
namespace Umbraco.Core.ObjectResolution
{
/// <summary>
/// A base class for lazily resolving types for a resolver
/// </summary>
/// <typeparam name="TResolver"></typeparam>
/// <typeparam name="TResolved"></typeparam>
/// <remarks>
/// 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.
/// </remarks>
internal abstract class LazyManyObjectsResolverBase<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
where TResolved : class
where TResolver : class
@@ -21,28 +34,62 @@ namespace Umbraco.Core.ObjectResolution
{
}
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
/// <summary>
/// Constructor accepting a list of lazy types
/// </summary>
/// <param name="listOfLazyTypes"></param>
/// <param name="scope"></param>
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
AddTypes(value);
AddTypes(listOfLazyTypes);
}
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> value)
/// <summary>
/// Constructor accepting a delegate to return a list of types
/// </summary>
/// <param name="typeListDelegate"></param>
/// <param name="scope"></param>
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
/// <summary>
/// Constructor accepting a list of lazy types
/// </summary>
/// <param name="httpContext"></param>
/// <param name="listOfLazyTypes"></param>
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> listOfLazyTypes)
: this(httpContext)
{
AddTypes(listOfLazyTypes);
}
/// <summary>
/// Constructor accepting a delegate to return a list of types
/// </summary>
/// <param name="httpContext"></param>
/// <param name="typeListDelegate"></param>
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListDelegate)
: this(httpContext)
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
#endregion
private readonly List<Lazy<Type>> _lazyTypes = new List<Lazy<Type>>();
private bool _hasResolvedTypes = false;
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
private readonly List<Func<IEnumerable<Type>>> _listOfTypeListDelegates = new List<Func<IEnumerable<Type>>>();
private List<Type> _resolvedTypes = null;
/// <summary>
/// Used for unit tests
/// </summary>
internal bool HasResolvedTypes
{
get { return _hasResolvedTypes; }
get { return _resolvedTypes != null; }
}
/// <summary>
@@ -52,28 +99,50 @@ namespace Umbraco.Core.ObjectResolution
{
get
{
var list = _lazyTypes.Select(x => x.Value).ToArray();
//we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
if (!_hasResolvedTypes)
using (var lck = GetUpgradeableReadLock())
{
var uniqueList = new List<Type>();
foreach (var l in list)
{
EnsureCorrectType(l);
if (uniqueList.Contains(l))
{
throw new InvalidOperationException("The Type " + l + " already exists in the collection");
}
uniqueList.Add(l);
}
_hasResolvedTypes = true;
}
var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
return list;
//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<Type>();
//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<Type> uniqueList, Type toAdd)
{
EnsureCorrectType(toAdd);
if (uniqueList.Contains(toAdd))
{
throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
}
uniqueList.Add(toAdd);
}
/// <summary>
/// Allows adding of multiple lazy types at once
/// </summary>
/// <param name="types"></param>
protected void AddTypes(IEnumerable<Lazy<Type>> types)
{
EnsureAddSupport();
@@ -84,11 +153,27 @@ namespace Umbraco.Core.ObjectResolution
{
foreach (var t in types)
{
_lazyTypes.Add(t);
_lazyTypeList.Add(t);
}
}
}
/// <summary>
/// Adds a type list delegate to the collection
/// </summary>
/// <param name="typeListDelegate"></param>
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListDelegate)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
}
/// <summary>
/// Adds a lazy type to the list
/// </summary>
@@ -101,7 +186,7 @@ namespace Umbraco.Core.ObjectResolution
using (GetWriteLock())
{
_lazyTypes.Add(value);
_lazyTypeList.Add(value);
}
}
@@ -125,7 +210,7 @@ namespace Umbraco.Core.ObjectResolution
using (GetWriteLock())
{
_lazyTypes.Clear();
_lazyTypeList.Clear();
}
}

View File

@@ -320,7 +320,16 @@ namespace Umbraco.Core.ObjectResolution
{
return new WriteLock(_lock);
}
/// <summary>
/// Returns an upgradeable read lock for use when reading/modifying collections
/// </summary>
/// <returns></returns>
protected UpgradeableReadLock GetUpgradeableReadLock()
{
return new UpgradeableReadLock(_lock);
}
/// <summary>
/// Throws an exception if resolution is frozen
/// </summary>