ResolutionStrategy
using Stashbox.Expressions;
using Stashbox.Lifetime;
using Stashbox.Registration;
using Stashbox.Resolution.Extensions;
using Stashbox.Utils;
using Stashbox.Utils.Data;
using Stashbox.Utils.Data.Immutable;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Stashbox.Resolution
{
internal class ResolutionStrategy : IResolutionStrategy
{
private readonly ExpressionBuilder expressionBuilder;
private ImmutableBucket<IResolver> resolverRepository = ImmutableBucket<IResolver>.Empty;
private ImmutableBucket<IResolver> lastChanceResolverRepository = ImmutableBucket<IResolver>.Empty;
public ResolutionStrategy(ExpressionBuilder expressionBuilder)
{
this.expressionBuilder = expressionBuilder;
}
public Expression BuildExpressionForType(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
if ((object)typeInformation.Type == Constants.ResolverType)
return resolutionContext.CurrentScopeParameter;
if (resolutionContext.ParameterExpressions.Length > 0) {
Type type = typeInformation.Type;
int num = resolutionContext.ParameterExpressions.Length;
while (num-- > 0) {
Pair<bool, ParameterExpression>[] array = resolutionContext.ParameterExpressions[num].WhereOrDefault(delegate(Pair<bool, ParameterExpression> p) {
if ((object)p.I2.Type != type)
return p.I2.Type.Implements(type);
return true;
});
if (array != null) {
Pair<bool, ParameterExpression> obj = array.FirstOrDefault((Pair<bool, ParameterExpression> parameter) => !parameter.I1) ?? array[array.Length - 1];
obj.I1 = true;
return obj.I2;
}
}
}
Stashbox.Utils.Data.Stack<ServiceRegistration> orDefault = resolutionContext.Decorators.GetOrDefault(typeInformation.Type, false);
if (orDefault != null)
return BuildExpressionForDecorator(orDefault.Pop(), resolutionContext.BeginDecoratingContext(typeInformation.Type, orDefault), typeInformation.Type, orDefault);
Expression expressionOverrideOrDefault = resolutionContext.GetExpressionOverrideOrDefault(typeInformation.Type, typeInformation.DependencyName);
if (expressionOverrideOrDefault != null)
return expressionOverrideOrDefault;
ServiceRegistration registrationOrDefault = resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationOrDefault(typeInformation, resolutionContext);
if (registrationOrDefault == null)
return BuildResolutionExpressionUsingResolvers(typeInformation, resolutionContext);
return BuildExpressionForRegistration(registrationOrDefault, resolutionContext, typeInformation);
}
public IEnumerable<Expression> BuildExpressionsForEnumerableRequest(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
IEnumerable<ServiceRegistration> registrationsOrDefault = resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationsOrDefault(typeInformation, resolutionContext);
if (registrationsOrDefault == null)
return BuildAllResolverExpressionsUsingResolvers(typeInformation, resolutionContext);
return registrationsOrDefault.Select(delegate(ServiceRegistration reg) {
Stashbox.Utils.Data.Stack<ServiceRegistration> orDefault = resolutionContext.Decorators.GetOrDefault(typeInformation.Type, false);
if (orDefault == null)
return BuildExpressionForRegistration(reg, resolutionContext, typeInformation);
orDefault.ReplaceBack(reg);
return BuildExpressionForDecorator(orDefault.Pop(), resolutionContext.BeginDecoratingContext(typeInformation.Type, orDefault), typeInformation.Type, orDefault);
});
}
public Expression BuildExpressionForTopLevelRequest(Type type, object name, ResolutionContext resolutionContext)
{
if ((object)type == Constants.ResolverType)
return resolutionContext.CurrentScopeParameter;
Expression expressionOverrideOrDefault = resolutionContext.GetExpressionOverrideOrDefault(type, name);
if (expressionOverrideOrDefault != null)
return expressionOverrideOrDefault;
ServiceRegistration registrationOrDefault = resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationOrDefault(type, resolutionContext, name);
if (registrationOrDefault == null)
return BuildResolutionExpressionUsingResolvers(new TypeInformation(type, name), resolutionContext);
return BuildExpressionForRegistration(registrationOrDefault, resolutionContext, new TypeInformation(type, name));
}
public Expression BuildExpressionForRegistration(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)
{
Type type = typeInformation.Type;
OpenGenericRegistration openGenericRegistration = serviceRegistration as OpenGenericRegistration;
if (openGenericRegistration != null)
serviceRegistration = openGenericRegistration.ProduceClosedRegistration(type);
IEnumerable<ServiceRegistration> decoratorsOrDefault = resolutionContext.CurrentContainerContext.DecoratorRepository.GetDecoratorsOrDefault(serviceRegistration.ImplementationType, typeInformation, resolutionContext);
if (decoratorsOrDefault == null)
return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, type, null);
Stashbox.Utils.Data.Stack<ServiceRegistration> stack = decoratorsOrDefault.AsStack();
stack.PushBack(serviceRegistration);
return BuildExpressionForDecorator(stack.Pop(), resolutionContext.BeginDecoratingContext(type, stack), type, stack);
}
public Expression BuildResolutionExpressionUsingResolvers(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
Expression expression = resolverRepository.BuildResolutionExpression(typeInfo, resolutionContext, this);
if (expression != null)
return expression;
return lastChanceResolverRepository.BuildResolutionExpression(typeInfo, resolutionContext, this);
}
public bool CanResolveType(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
if (!resolverRepository.CanResolve(typeInfo, resolutionContext))
return lastChanceResolverRepository.CanResolve(typeInfo, resolutionContext);
return true;
}
public void RegisterResolver(IResolver resolver)
{
Swap.SwapValue<IResolver, byte, byte, byte, ImmutableBucket<IResolver>>(ref resolverRepository, (IResolver t1, byte t2, byte t3, byte t4, ImmutableBucket<IResolver> repo) => repo.Add(t1), resolver, 0, 0, 0);
}
public void RegisterLastChanceResolver(IResolver resolver)
{
Swap.SwapValue<IResolver, byte, byte, byte, ImmutableBucket<IResolver>>(ref lastChanceResolverRepository, (IResolver t1, byte t2, byte t3, byte t4, ImmutableBucket<IResolver> repo) => repo.Add(t1), resolver, 0, 0, 0);
}
private IEnumerable<Expression> BuildAllResolverExpressionsUsingResolvers(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
return resolverRepository.BuildAllResolutionExpressions(typeInfo, resolutionContext, this) ?? lastChanceResolverRepository.BuildAllResolutionExpressions(typeInfo, resolutionContext, this);
}
private Expression BuildExpressionForDecorator(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType, Stashbox.Utils.Data.Stack<ServiceRegistration> decorators)
{
OpenGenericRegistration openGenericRegistration = serviceRegistration as OpenGenericRegistration;
if (openGenericRegistration != null)
serviceRegistration = openGenericRegistration.ProduceClosedRegistration(requestedType);
return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, requestedType, decorators.PeekBack()?.RegistrationContext.Lifetime);
}
private Expression BuildExpressionAndApplyLifetime(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType, LifetimeDescriptor secondaryLifetimeDescriptor = null)
{
LifetimeDescriptor lifetimeDescriptor = serviceRegistration.RegistrationContext.Lifetime ?? secondaryLifetimeDescriptor;
if (!IsOutputLifetimeManageable(serviceRegistration) || lifetimeDescriptor == null)
return expressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, requestedType);
return lifetimeDescriptor.ApplyLifetime(expressionBuilder, serviceRegistration, resolutionContext, requestedType);
}
private static bool IsOutputLifetimeManageable(ServiceRegistration serviceRegistration)
{
if (serviceRegistration.RegistrationType != RegistrationType.OpenGeneric)
return serviceRegistration.RegistrationType != RegistrationType.Instance;
return false;
}
}
}