Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="3.1.2-preview-555" />

 ResolutionScope

using Stashbox.Exceptions; using Stashbox.Expressions; using Stashbox.Resolution; using Stashbox.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; namespace Stashbox { internal sealed class ResolutionScope : IResolutionScope, IDisposable, IDependencyResolver { private class DelegateCache { public ImmutableTree<object, Func<IResolutionScope, object>> ServiceDelegates = ImmutableTree<object, Func<IResolutionScope, object>>.Empty; public ImmutableTree<object, Func<IResolutionScope, Delegate>> FactoryDelegates = ImmutableTree<object, Func<IResolutionScope, Delegate>>.Empty; } private class DisposableItem { public IDisposable Item; public DisposableItem Next; public static readonly DisposableItem Empty = new DisposableItem(); } private class FinalizableItem { public object Item; public Action<object> Finalizer; public FinalizableItem Next; public static readonly FinalizableItem Empty = new FinalizableItem(); } private readonly ResolutionStrategy resolutionStrategy; private readonly ExpressionFactory expressionFactory; private readonly IContainerContext containerContext; private int disposed; private DisposableItem rootItem = DisposableItem.Empty; private FinalizableItem rootFinalizableItem = FinalizableItem.Empty; private ImmutableTree<object> scopedItems = ImmutableTree<object>.Empty; private ImmutableTree<Type, ImmutableTree<object, object>> scopedInstances = ImmutableTree<Type, ImmutableTree<object, object>>.Empty; private ImmutableTree<ThreadLocal<bool>> circularDependencyBarrier = ImmutableTree<ThreadLocal<bool>>.Empty; private DelegateCache delegateCache; public object Name { get; } public IResolutionScope ParentScope { get; } private ResolutionScope(ResolutionStrategy resolutionStrategy, ExpressionFactory expressionBuilder, IContainerContext containerContext, DelegateCache delegateCache, object name) { this.resolutionStrategy = resolutionStrategy; expressionFactory = expressionBuilder; this.containerContext = containerContext; Name = name; this.delegateCache = delegateCache; } internal ResolutionScope(ResolutionStrategy resolutionStrategy, ExpressionFactory expressionBuilder, IContainerContext containerContext) : this(resolutionStrategy, expressionBuilder, containerContext, new DelegateCache(), null) { } private ResolutionScope(ResolutionStrategy resolutionStrategy, ExpressionFactory expressionBuilder, IContainerContext containerContext, IResolutionScope parent, DelegateCache delegateCache, object name = null) : this(resolutionStrategy, expressionBuilder, containerContext, delegateCache, name) { ParentScope = parent; } public object Resolve(Type typeFrom, bool nullResultAllowed = false, object[] dependencyOverrides = null) { if (dependencyOverrides != null) return Activate(new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, nullResultAllowed, ProcessDependencyOverrides(dependencyOverrides)), typeFrom, null); Func<IResolutionScope, object> orDefault = delegateCache.ServiceDelegates.GetOrDefault(typeFrom); if (orDefault == null) return Activate(new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, nullResultAllowed, ProcessDependencyOverrides(dependencyOverrides)), typeFrom, null); return orDefault(this); } public object Resolve(Type typeFrom, object name, bool nullResultAllowed = false, object[] dependencyOverrides = null) { if (dependencyOverrides != null) return Activate(new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, nullResultAllowed, ProcessDependencyOverrides(dependencyOverrides)), typeFrom, null); Func<IResolutionScope, object> orDefault = delegateCache.ServiceDelegates.GetOrDefault(name); if (orDefault == null) return Activate(new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, nullResultAllowed, ProcessDependencyOverrides(dependencyOverrides)), typeFrom, name); return orDefault(this); } public IEnumerable<TKey> ResolveAll<TKey>(object[] dependencyOverrides = null) { return (IEnumerable<TKey>)Resolve(typeof(IEnumerable<TKey>), false, dependencyOverrides); } public IEnumerable<object> ResolveAll(Type typeFrom, object[] dependencyOverrides = null) { return (IEnumerable<object>)Resolve(typeof(IEnumerable<>).MakeGenericType(typeFrom), false, dependencyOverrides); } public Delegate ResolveFactory(Type typeFrom, object name = null, bool nullResultAllowed = false, params Type[] parameterTypes) { object key = name ?? typeFrom; Func<IResolutionScope, Delegate> orDefault = delegateCache.FactoryDelegates.GetOrDefault(key); if (orDefault == null) return ActivateFactoryDelegate(typeFrom, parameterTypes, name, nullResultAllowed); return orDefault(this); } public IDependencyResolver BeginScope(object name = null, bool attachToParent = false) { ResolutionScope resolutionScope = new ResolutionScope(resolutionStrategy, expressionFactory, containerContext, this, delegateCache, name); if (!attachToParent) return resolutionScope; return AddDisposableTracking(resolutionScope); } public IDependencyResolver PutInstanceInScope(Type typeFrom, object instance, bool withoutDisposalTracking = false, object name = null) { Shield.EnsureNotNull(typeFrom, "typeFrom"); Shield.EnsureNotNull(instance, "instance"); object obj = name ?? typeFrom; ImmutableTree<object, object> t5 = ImmutableTree<object, object>.Empty.AddOrUpdate(obj, instance, null); Swap.SwapValue(ref scopedInstances, (Type t1, object t2, ImmutableTree<object, object> t3, object t4, ImmutableTree<Type, ImmutableTree<object, object>> instances) => instances.AddOrUpdate(t1, t3, (ImmutableTree<object, object> old, ImmutableTree<object, object> new) => old.AddOrUpdate(t4, t2, true)), typeFrom, instance, t5, obj); if (!withoutDisposalTracking) { IDisposable disposable = instance as IDisposable; if (disposable != null) AddDisposableTracking(disposable); } delegateCache = new DelegateCache(); return this; } public TTo BuildUp<TTo>(TTo instance) { ResolutionContext resolutionContext = new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, false, null); return (TTo)expressionFactory.ConstructBuildUpExpression(resolutionContext, instance.AsConstant(), typeof(TTo)).CompileDelegate(resolutionContext, containerContext.ContainerConfiguration)(this); } public object Activate(Type type, params object[] arguments) { if (!type.IsResolvableType()) throw new ArgumentException("The given type (" + type.FullName + ") could not be activated on the fly by the container."); ResolutionContext resolutionContext = new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, false, ProcessDependencyOverrides(arguments)); return expressionFactory.ConstructExpression(resolutionContext, type).CompileDelegate(resolutionContext, containerContext.ContainerConfiguration)(this); } public TDisposable AddDisposableTracking<TDisposable>(TDisposable disposable) where TDisposable : IDisposable { Swap.SwapValue<TDisposable, byte, byte, byte, DisposableItem>(ref rootItem, (TDisposable t1, byte t2, byte t3, byte t4, DisposableItem root) => new DisposableItem { Item = (object)t1, Next = root }, disposable, 0, 0, 0); return disposable; } public TService AddWithFinalizer<TService>(TService finalizable, Action<TService> finalizer) { Swap.SwapValue<TService, Action<TService>, byte, byte, FinalizableItem>(ref rootFinalizableItem, (TService t1, Action<TService> t2, byte t3, byte t4, FinalizableItem root) => new FinalizableItem { Item = (object)t1, Finalizer = (Action<object>)delegate(object f) { t2((TService)f); }, Next = root }, finalizable, finalizer, 0, 0); return finalizable; } public object GetOrAddScopedObject(int key, object sync, Func<IResolutionScope, object> factory) { object orDefault = scopedItems.GetOrDefault(key); if (orDefault != null) return orDefault; lock (sync) { orDefault = scopedItems.GetOrDefault(key); if (orDefault == null) { orDefault = factory(this); Swap.SwapValue<int, object, byte, byte, ImmutableTree<object>>(ref scopedItems, (int t1, object t2, byte t3, byte t4, ImmutableTree<object> items) => items.AddOrUpdate(t1, t2, null), key, orDefault, 0, 0); return orDefault; } return orDefault; } } public void InvalidateDelegateCache() { delegateCache.ServiceDelegates = ImmutableTree<object, Func<IResolutionScope, object>>.Empty; delegateCache.FactoryDelegates = ImmutableTree<object, Func<IResolutionScope, Delegate>>.Empty; } public IEnumerable<object> GetActiveScopeNames() { for (IResolutionScope current = this; current != null; current = current.ParentScope) { if (current.Name != null) yield return current.Name; } } public void CheckRuntimeCircularDependencyBarrier(int key, Type type) { ThreadLocal<bool> orDefault = circularDependencyBarrier.GetOrDefault(key); if (orDefault != null && orDefault.Value) throw new CircularDependencyException(type, null); Swap.SwapValue<int, byte, byte, byte, ImmutableTree<ThreadLocal<bool>>>(ref circularDependencyBarrier, (int t1, byte t2, byte t3, byte t4, ImmutableTree<ThreadLocal<bool>> barrier) => barrier.AddOrUpdate(t1, new ThreadLocal<bool>(), delegate(ThreadLocal<bool> old, ThreadLocal<bool> new) { old.Value = true; return old; }), key, 0, 0, 0); } public void ResetRuntimeCircularDependencyBarrier(int key) { ThreadLocal<bool> orDefault = circularDependencyBarrier.GetOrDefault(key); if (orDefault != null) orDefault.Value = false; } public void Dispose() { if (Interlocked.CompareExchange(ref disposed, 1, 0) == 0) { for (FinalizableItem next = rootFinalizableItem; next != FinalizableItem.Empty; next = next.Next) { next.Finalizer(next.Item); } for (DisposableItem next2 = rootItem; next2 != DisposableItem.Empty; next2 = next2.Next) { next2.Item.Dispose(); } if (!circularDependencyBarrier.IsEmpty) { foreach (KeyValuePair<int, ThreadLocal<bool>> item in circularDependencyBarrier.Walk()) { item.Value.Dispose(); } } } } private object Activate(ResolutionContext resolutionContext, Type type, object name = null) { Expression expression = resolutionStrategy.BuildExpressionForTopLevelRequest(type, name, resolutionContext); if (expression == null) { if (resolutionContext.NullResultAllowed) return null; throw new ResolutionFailedException(type, "Service is not registered or unresolvable type requested.", null); } Func<IResolutionScope, object> func = expression.CompileDelegate(resolutionContext, containerContext.ContainerConfiguration); if (resolutionContext.FactoryDelegateCacheEnabled) Swap.SwapValue<object, Func<IResolutionScope, object>, byte, byte, ImmutableTree<object, Func<IResolutionScope, object>>>(ref delegateCache.ServiceDelegates, (object t1, Func<IResolutionScope, object> t2, byte t3, byte t4, ImmutableTree<object, Func<IResolutionScope, object>> c) => c.AddOrUpdate(t1, t2, null), name ?? type, func, 0, 0); return func(this); } private Delegate ActivateFactoryDelegate(Type type, Type[] parameterTypes, object name, bool nullResultAllowed) { ResolutionContext resolutionContext = new ResolutionContext(GetActiveScopeNames(), containerContext, resolutionStrategy, this == containerContext.RootScope, nullResultAllowed, null).BeginContextWithFunctionParameters(from p in parameterTypes select p.AsParameter(null)); Expression expression = resolutionStrategy.BuildExpressionForTopLevelRequest(type, name, resolutionContext); if (expression == null) { if (resolutionContext.NullResultAllowed) return null; throw new ResolutionFailedException(type, "Service is not registered or unresolvable type requested.", null); } Func<IResolutionScope, Delegate> func = expression.AsLambda(resolutionContext.ParameterExpressions.SelectMany((IEnumerable<Pair<bool, ParameterExpression>> x) => from i in x select i.I2)).CompileDynamicDelegate(resolutionContext, containerContext.ContainerConfiguration); Swap.SwapValue<object, Func<IResolutionScope, Delegate>, byte, byte, ImmutableTree<object, Func<IResolutionScope, Delegate>>>(ref delegateCache.FactoryDelegates, (object t1, Func<IResolutionScope, Delegate> t2, byte t3, byte t4, ImmutableTree<object, Func<IResolutionScope, Delegate>> c) => c.AddOrUpdate(t1, t2, null), name ?? type, func, 0, 0); return func(this); } private HashTree<Type, HashTree<object, Expression>> ProcessDependencyOverrides(object[] dependencyOverrides) { if (dependencyOverrides == null && scopedInstances.IsEmpty) return null; HashTree<Type, HashTree<object, Expression>> hashTree = new HashTree<Type, HashTree<object, Expression>>(); if (!scopedInstances.IsEmpty) { foreach (KeyValuePair<Type, ImmutableTree<object, object>> item in scopedInstances.Walk()) { HashTree<object, Expression> hashTree2 = new HashTree<object, Expression>(); foreach (KeyValuePair<object, object> item2 in item.Value.Walk()) { hashTree2.Add(item2.Key, item2.Value.AsConstant(), false); } hashTree.Add(item.Key, hashTree2, true); } } if (dependencyOverrides == null) return hashTree; foreach (object obj in dependencyOverrides) { Type type = obj.GetType(); ConstantExpression value = obj.AsConstant(); HashTree<object, Expression> orDefault = hashTree.GetOrDefault(type, true); if (orDefault == null) hashTree.Add(type, new HashTree<object, Expression>(type, value), true); else orDefault.Add(type, value, false); foreach (Type item3 in type.GetRegisterableInterfaceTypes().Concat(type.GetRegisterableBaseTypes())) { orDefault = hashTree.GetOrDefault(item3, true); if (orDefault == null) hashTree.Add(item3, new HashTree<object, Expression>(item3, value), true); else orDefault.Add(item3, value, false); } } return hashTree; } } }