ResolutionContext
Represents information about the actual resolution flow.
using Stashbox.Registration;
using Stashbox.Utils;
using Stashbox.Utils.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace Stashbox.Resolution
{
public class ResolutionContext
{
internal class PerRequestConfiguration
{
public bool RequiresRequestContext { get; set; }
public bool FactoryDelegateCacheEnabled { get; set; }
}
private Tree<Expression> expressionCache;
private readonly Tree<Func<IResolutionScope, IRequestContext, object>> factoryCache;
private readonly HashTree<object, ConstantExpression> expressionOverrides;
private readonly Stashbox.Utils.Data.Stack<int> circularDependencyBarrier;
internal ExpandableArray<Expression> SingleInstructions { get; set; }
internal Tree<ParameterExpression> DefinedVariables { get; set; }
internal ExpandableArray<Pair<bool, ParameterExpression>[]> ParameterExpressions { get; set; }
internal ExpandableArray<Type, Stashbox.Utils.Data.Stack<ServiceRegistration>> RemainingDecorators { get; set; }
internal ExpandableArray<ServiceRegistration> CurrentDecorators { get; set; }
internal int CurrentLifeSpan { get; set; }
internal string NameOfServiceLifeSpanValidatingAgainst { get; set; }
internal bool PerResolutionRequestCacheEnabled { get; set; }
internal bool UnknownTypeCheckDisabled { get; set; }
internal bool ShouldFallBackToRequestInitiatorContext { get; set; }
internal bool IsTopRequest { get; set; }
internal Stashbox.Utils.Data.Stack<object> ScopeNames { get; }
internal IContainerContext RequestInitiatorContainerContext { get; }
internal PerRequestConfiguration RequestConfiguration { get; }
public bool NullResultAllowed { get; }
public bool IsRequestedFromRoot { get; }
public ParameterExpression CurrentScopeParameter { get; set; }
public ParameterExpression RequestContextParameter { get; set; }
public IContainerContext CurrentContainerContext { get; set; }
private ResolutionContext(IEnumerable<object> initialScopeNames, IContainerContext currentContainerContext, bool isTopLevel, bool isRequestedFromRoot, bool nullResultAllowed, HashTree<object, ConstantExpression> dependencyOverrides, ParameterExpression[] initialParameters)
{
RequestConfiguration = new PerRequestConfiguration();
IsTopRequest = isTopLevel;
DefinedVariables = new Tree<ParameterExpression>();
SingleInstructions = new ExpandableArray<Expression>();
RemainingDecorators = new ExpandableArray<Type, Stashbox.Utils.Data.Stack<ServiceRegistration>>();
CurrentDecorators = new ExpandableArray<ServiceRegistration>();
expressionOverrides = dependencyOverrides;
NullResultAllowed = nullResultAllowed;
CurrentScopeParameter = Constants.ResolutionScopeParameter;
RequestContextParameter = Constants.RequestContextParameter;
ParameterExpressions = ((initialParameters != null) ? new ExpandableArray<Pair<bool, ParameterExpression>[]> {
initialParameters.AsParameterPairs()
} : new ExpandableArray<Pair<bool, ParameterExpression>[]>());
ScopeNames = initialScopeNames.AsStack();
circularDependencyBarrier = new Stashbox.Utils.Data.Stack<int>();
expressionCache = new Tree<Expression>();
factoryCache = new Tree<Func<IResolutionScope, IRequestContext, object>>();
IsRequestedFromRoot = isRequestedFromRoot;
CurrentContainerContext = (RequestInitiatorContainerContext = currentContainerContext);
PerRequestConfiguration requestConfiguration = RequestConfiguration;
bool factoryDelegateCacheEnabled = PerResolutionRequestCacheEnabled = (dependencyOverrides == null);
requestConfiguration.FactoryDelegateCacheEnabled = factoryDelegateCacheEnabled;
}
public void AddInstruction(Expression instruction)
{
SingleInstructions.Add(instruction);
}
public void AddDefinedVariable(int key, ParameterExpression parameter)
{
DefinedVariables.Add(key, parameter);
}
public void AddDefinedVariable(ParameterExpression parameter)
{
DefinedVariables.Add(RuntimeHelpers.GetHashCode(parameter), parameter);
}
public ParameterExpression GetKnownVariableOrDefault(int key)
{
return DefinedVariables.GetOrDefault(key);
}
internal void CacheExpression(int key, Expression expression)
{
expressionCache.Add(key, expression);
}
internal Expression GetCachedExpression(int key)
{
return expressionCache.GetOrDefault(key);
}
internal void CacheFactory(int key, Func<IResolutionScope, IRequestContext, object> factory)
{
factoryCache.Add(key, factory);
}
internal Func<IResolutionScope, IRequestContext, object> GetCachedFactory(int key)
{
return factoryCache.GetOrDefault(key);
}
internal ConstantExpression GetExpressionOverrideOrDefault(Type type, object name = null)
{
return expressionOverrides?.GetOrDefaultByValue(name ?? type);
}
internal bool WeAreInCircle(int key)
{
return circularDependencyBarrier.Contains(key);
}
internal void PullOutCircularDependencyBarrier(int key)
{
circularDependencyBarrier.Add(key);
}
internal void LetDownCircularDependencyBarrier()
{
circularDependencyBarrier.Pop();
}
internal static ResolutionContext BeginTopLevelContext(IEnumerable<object> initialScopeNames, IContainerContext currentContainerContext, bool isRequestedFromRoot, HashTree<object, ConstantExpression> dependencyOverrides = null, ParameterExpression[] initialParameters = null)
{
return new ResolutionContext(initialScopeNames, currentContainerContext, true, isRequestedFromRoot, false, dependencyOverrides, initialParameters);
}
internal static ResolutionContext BeginNullableTopLevelContext(IEnumerable<object> initialScopeNames, IContainerContext currentContainerContext, bool isRequestedFromRoot, HashTree<object, ConstantExpression> dependencyOverrides = null, ParameterExpression[] initialParameters = null)
{
return new ResolutionContext(initialScopeNames, currentContainerContext, true, isRequestedFromRoot, true, dependencyOverrides, initialParameters);
}
internal static ResolutionContext BeginValidationContext(IContainerContext currentContainerContext)
{
return new ResolutionContext(Constants.EmptyArray<object>(), currentContainerContext, true, false, false, null, null);
}
internal ResolutionContext BeginSubDependencyContext()
{
if (!IsTopRequest)
return this;
ResolutionContext resolutionContext = Clone();
resolutionContext.IsTopRequest = false;
return resolutionContext;
}
internal ResolutionContext BeginCrossContainerContext(IContainerContext currentContainerContext)
{
ResolutionContext resolutionContext = Clone();
resolutionContext.CurrentContainerContext = currentContainerContext;
resolutionContext.ShouldFallBackToRequestInitiatorContext = (resolutionContext.RequestInitiatorContainerContext != currentContainerContext);
return resolutionContext;
}
internal ResolutionContext BeginNewScopeContext(ReadOnlyKeyValue<object, ParameterExpression> scopeParameter)
{
ScopeNames.PushBack(scopeParameter.Key);
ResolutionContext resolutionContext = BeginSubGraph();
resolutionContext.CurrentScopeParameter = scopeParameter.Value;
return resolutionContext;
}
internal ResolutionContext BeginSubGraph()
{
ResolutionContext resolutionContext = Clone();
resolutionContext.DefinedVariables = new Tree<ParameterExpression>();
resolutionContext.SingleInstructions = new ExpandableArray<Expression>();
resolutionContext.expressionCache = new Tree<Expression>();
return resolutionContext;
}
internal ResolutionContext BeginUnknownTypeCheckDisabledContext()
{
if (UnknownTypeCheckDisabled)
return this;
ResolutionContext resolutionContext = Clone();
resolutionContext.UnknownTypeCheckDisabled = true;
return resolutionContext;
}
internal ResolutionContext BeginContextWithFunctionParameters(ParameterExpression[] parameterExpressions)
{
ResolutionContext resolutionContext = Clone();
resolutionContext.ParameterExpressions = new ExpandableArray<Pair<bool, ParameterExpression>[]>(ParameterExpressions) {
parameterExpressions.AsParameterPairs()
};
resolutionContext.PerResolutionRequestCacheEnabled = false;
return resolutionContext;
}
internal ResolutionContext BeginDecoratingContext(Type decoratingType, Stashbox.Utils.Data.Stack<ServiceRegistration> serviceRegistrations)
{
ResolutionContext resolutionContext = Clone();
Stashbox.Utils.Data.Stack<ServiceRegistration> stack = new Stashbox.Utils.Data.Stack<ServiceRegistration>(serviceRegistrations);
ServiceRegistration item = stack.Pop();
resolutionContext.CurrentDecorators = new ExpandableArray<ServiceRegistration>(CurrentDecorators) {
item
};
resolutionContext.RemainingDecorators = new ExpandableArray<Type, Stashbox.Utils.Data.Stack<ServiceRegistration>>(RemainingDecorators);
resolutionContext.RemainingDecorators.AddOrUpdate(decoratingType, stack);
return resolutionContext;
}
internal ResolutionContext BeginLifetimeValidationContext(int lifeSpan, string currentlyLifeSpanValidatingService)
{
ResolutionContext resolutionContext = Clone();
resolutionContext.CurrentLifeSpan = lifeSpan;
resolutionContext.NameOfServiceLifeSpanValidatingAgainst = currentlyLifeSpanValidatingService;
return resolutionContext;
}
private ResolutionContext Clone()
{
return (ResolutionContext)MemberwiseClone();
}
}
}