ResolutionStrategy
using Stashbox.Expressions;
using Stashbox.Lifetime;
using Stashbox.Registration;
using Stashbox.Resolution.Resolvers;
using Stashbox.Resolution.Wrappers;
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 ImmutableBucket<IResolver> resolverRepository = new ImmutableBucket<IResolver>(new IResolver[9] {
new EnumerableWrapper(),
new LazyWrapper(),
new FuncWrapper(),
new MetadataWrapper(),
new KeyValueWrapper(),
new OptionalValueResolver(),
new DefaultValueResolver(),
new ParentContainerResolver(),
new UnknownTypeResolver()
});
public ServiceContext BuildExpressionForType(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
if (typeInformation.Type == Constants.ResolverType || typeInformation.Type == Constants.ServiceProviderType)
return resolutionContext.CurrentScopeParameter.AsServiceContext(null);
if (typeInformation.Type == Constants.RequestContextType)
return resolutionContext.RequestContextParameter.AsServiceContext(null);
if (!resolutionContext.IsTopRequest) {
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 (!(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.AsServiceContext(null);
}
}
}
Stashbox.Utils.Data.Stack<ServiceRegistration> orDefaultByRef = resolutionContext.RemainingDecorators.GetOrDefaultByRef(typeInformation.Type);
if (orDefaultByRef != null && orDefaultByRef.Length > 0)
return BuildExpressionForDecorator(orDefaultByRef.Front(), resolutionContext.BeginDecoratingContext(typeInformation.Type, orDefaultByRef), typeInformation.Type, orDefaultByRef).AsServiceContext(null);
}
ConstantExpression expressionOverrideOrDefault = resolutionContext.GetExpressionOverrideOrDefault(typeInformation.Type, typeInformation.DependencyName);
if (expressionOverrideOrDefault != null)
return expressionOverrideOrDefault.AsServiceContext(null);
ServiceRegistration registrationOrDefault = resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationOrDefault(typeInformation, resolutionContext);
resolutionContext = resolutionContext.BeginSubDependencyContext();
if (registrationOrDefault == null)
return BuildExpressionUsingWrappersOrResolvers(resolutionContext, typeInformation);
return BuildExpressionForRegistration(registrationOrDefault, resolutionContext, typeInformation);
}
public IEnumerable<ServiceContext> BuildExpressionsForEnumerableRequest(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
IEnumerable<ServiceRegistration> registrationsOrDefault = resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationsOrDefault(typeInformation, resolutionContext);
if (registrationsOrDefault == null)
return BuildEnumerableExpressionUsingWrappersOrResolvers(resolutionContext, typeInformation);
return registrationsOrDefault.Select(delegate(ServiceRegistration registration) {
Stashbox.Utils.Data.Stack<ServiceRegistration> orDefaultByRef = resolutionContext.RemainingDecorators.GetOrDefaultByRef(typeInformation.Type);
if (orDefaultByRef == null || orDefaultByRef.Length == 0)
return BuildExpressionForRegistration(registration, resolutionContext, typeInformation);
orDefaultByRef.ReplaceBack(registration);
return BuildExpressionForDecorator(orDefaultByRef.Front(), resolutionContext.BeginDecoratingContext(typeInformation.Type, orDefaultByRef), typeInformation.Type, orDefaultByRef).AsServiceContext(registration);
});
}
public ServiceContext BuildExpressionForRegistration(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)
{
Type type = typeInformation.Type;
OpenGenericRegistration openGenericRegistration = serviceRegistration as OpenGenericRegistration;
if (openGenericRegistration != null)
serviceRegistration = openGenericRegistration.ProduceClosedRegistration(type, resolutionContext);
IEnumerable<ServiceRegistration> decoratorsOrDefault = resolutionContext.CurrentContainerContext.DecoratorRepository.GetDecoratorsOrDefault(serviceRegistration.ImplementationType, typeInformation, resolutionContext);
if (decoratorsOrDefault == null)
return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, type, null).AsServiceContext(serviceRegistration);
Stashbox.Utils.Data.Stack<ServiceRegistration> stack = decoratorsOrDefault.AsStack();
stack.PushBack(serviceRegistration);
return BuildExpressionForDecorator(stack.Front(), resolutionContext.BeginDecoratingContext(type, stack), type, stack).AsServiceContext(serviceRegistration);
}
public bool IsTypeResolvable(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
if (typeInformation.Type.IsGenericTypeDefinition)
return false;
if (typeInformation.Type == Constants.ResolverType || typeInformation.Type == Constants.ServiceProviderType || typeInformation.Type == Constants.RequestContextType)
return true;
if (resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(typeInformation.Type, typeInformation.DependencyName, true) || IsWrappedTypeRegistered(typeInformation, resolutionContext))
return true;
if (resolutionContext.GetExpressionOverrideOrDefault(typeInformation.Type, typeInformation.DependencyName) == null)
return CanLookupService(typeInformation, resolutionContext);
return true;
}
public void RegisterResolver(IResolver resolver)
{
Swap.SwapValue<IResolver, byte, byte, byte, ImmutableBucket<IResolver>>(ref resolverRepository, (IResolver t1, byte _, byte _, byte _, ImmutableBucket<IResolver> repo) => repo.Insert(repo.Length - 4, t1), resolver, 0, 0, 0);
}
private ServiceContext BuildExpressionUsingWrappersOrResolvers(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
int length = resolverRepository.Length;
for (int i = 0; i < length; i++) {
IResolver resolver = resolverRepository[i];
IEnumerableWrapper enumerableWrapper = resolver as IEnumerableWrapper;
if (enumerableWrapper != null) {
IEnumerableWrapper enumerableWrapper2 = enumerableWrapper;
if (enumerableWrapper2.TryUnWrap(typeInformation, out TypeInformation unWrappedType))
return enumerableWrapper2.WrapExpression(typeInformation, unWrappedType, BuildExpressionsForEnumerableRequest(resolutionContext, unWrappedType)).AsServiceContext(null);
}
IServiceWrapper serviceWrapper = resolver as IServiceWrapper;
if (serviceWrapper != null) {
IServiceWrapper serviceWrapper2 = serviceWrapper;
if (serviceWrapper2.TryUnWrap(typeInformation, out TypeInformation unWrappedType2)) {
ServiceContext serviceContext = BuildExpressionForType(resolutionContext, unWrappedType2);
if (serviceContext != null)
return serviceWrapper2.WrapExpression(typeInformation, unWrappedType2, serviceContext).AsServiceContext(serviceContext.ServiceRegistration);
return null;
}
}
IParameterizedWrapper parameterizedWrapper = resolver as IParameterizedWrapper;
if (parameterizedWrapper != null) {
IParameterizedWrapper parameterizedWrapper2 = parameterizedWrapper;
if (parameterizedWrapper2.TryUnWrap(typeInformation, out TypeInformation unWrappedType3, out IEnumerable<Type> parameterTypes)) {
ParameterExpression[] parameterExpressions = (from p in parameterTypes
select p.AsParameter(null)).CastToArray();
ServiceContext serviceContext2 = BuildExpressionForType(resolutionContext.BeginContextWithFunctionParameters(parameterExpressions), unWrappedType3);
if (serviceContext2 != null)
return parameterizedWrapper2.WrapExpression(typeInformation, unWrappedType3, serviceContext2, parameterExpressions).AsServiceContext(serviceContext2.ServiceRegistration);
return null;
}
}
}
return BuildExpressionUsingResolvers(resolutionContext, typeInformation);
}
private IEnumerable<ServiceContext> BuildEnumerableExpressionUsingWrappersOrResolvers(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
int length = resolverRepository.Length;
for (int i = 0; i < length; i++) {
IResolver resolver = resolverRepository[i];
IResolver resolver2 = resolver;
IServiceWrapper serviceWrapper = resolver2 as IServiceWrapper;
if (serviceWrapper != null) {
IServiceWrapper serviceWrapper2 = serviceWrapper;
if (serviceWrapper2.TryUnWrap(typeInformation, out TypeInformation unWrappedType))
return from serviceContext in BuildExpressionsForEnumerableRequest(resolutionContext, unWrappedType)
select serviceWrapper2.WrapExpression(typeInformation, unWrappedType, serviceContext).AsServiceContext(serviceContext.ServiceRegistration);
}
IParameterizedWrapper parameterizedWrapper = resolver2 as IParameterizedWrapper;
if (parameterizedWrapper != null) {
IParameterizedWrapper parameterizedWrapper2 = parameterizedWrapper;
if (parameterizedWrapper2.TryUnWrap(typeInformation, out TypeInformation unWrappedType2, out IEnumerable<Type> parameterTypes)) {
ParameterExpression[] parameterExpressions = (from p in parameterTypes
select p.AsParameter(null)).CastToArray();
return from serviceContext in BuildExpressionsForEnumerableRequest(resolutionContext.BeginContextWithFunctionParameters(parameterExpressions), unWrappedType2)
select parameterizedWrapper2.WrapExpression(typeInformation, unWrappedType2, serviceContext, parameterExpressions).AsServiceContext(serviceContext.ServiceRegistration);
}
}
}
return BuildEnumerableExpressionsUsingResolvers(resolutionContext, typeInformation);
}
private ServiceContext BuildExpressionUsingResolvers(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
int length = resolverRepository.Length;
for (int i = 0; i < length; i++) {
IServiceResolver serviceResolver = resolverRepository[i] as IServiceResolver;
if (serviceResolver != null && serviceResolver.CanUseForResolution(typeInformation, resolutionContext))
return serviceResolver.GetExpression(this, typeInformation, resolutionContext);
}
return null;
}
private IEnumerable<ServiceContext> BuildEnumerableExpressionsUsingResolvers(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
int length = resolverRepository.Length;
for (int i = 0; i < length; i++) {
IEnumerableSupportedResolver enumerableSupportedResolver = resolverRepository[i] as IEnumerableSupportedResolver;
if (enumerableSupportedResolver != null && enumerableSupportedResolver.CanUseForResolution(typeInformation, resolutionContext))
return enumerableSupportedResolver.GetExpressionsForEnumerableRequest(this, typeInformation, resolutionContext);
}
return Constants.EmptyArray<ServiceContext>();
}
private bool IsWrappedTypeRegistered(TypeInformation typeInformation, ResolutionContext resolutionContext)
{
int length = resolverRepository.Length;
int num = 0;
while (num < length) {
IResolver resolver = resolverRepository[num];
IEnumerableWrapper enumerableWrapper = resolver as IEnumerableWrapper;
if (enumerableWrapper == null || !enumerableWrapper.TryUnWrap(typeInformation, out TypeInformation _)) {
IServiceWrapper serviceWrapper = resolver as IServiceWrapper;
TypeInformation unWrappedType2;
if (serviceWrapper == null || !serviceWrapper.TryUnWrap(typeInformation, out unWrappedType2) || !resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(unWrappedType2.Type, typeInformation.DependencyName, true)) {
IParameterizedWrapper parameterizedWrapper = resolver as IParameterizedWrapper;
TypeInformation unWrappedType3;
if (parameterizedWrapper == null || !parameterizedWrapper.TryUnWrap(typeInformation, out unWrappedType3, out IEnumerable<Type> _) || !resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(unWrappedType3.Type, typeInformation.DependencyName, true)) {
num++;
continue;
}
}
}
return true;
}
return false;
}
private bool CanLookupService(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
int length = resolverRepository.Length;
for (int i = 0; i < length; i++) {
ILookup lookup = resolverRepository[i] as ILookup;
if (lookup != null && lookup.CanLookupService(typeInfo, resolutionContext))
return true;
}
return false;
}
private static 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, resolutionContext);
return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, requestedType, decorators.PeekBack()?.RegistrationContext.Lifetime);
}
private static 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(serviceRegistration, resolutionContext, requestedType);
}
private static bool IsOutputLifetimeManageable(ServiceRegistration serviceRegistration)
{
if (serviceRegistration.RegistrationType != RegistrationType.OpenGeneric)
return serviceRegistration.RegistrationType != RegistrationType.Instance;
return false;
}
}
}