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; } } } }