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;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Stashbox.Resolution
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal class ResolutionStrategy : IResolutionStrategy
{
private readonly ParentContainerResolver parentContainerResolver;
private ImmutableBucket<IResolver> resolverRepository;
public ResolutionStrategy()
{
parentContainerResolver = new ParentContainerResolver();
resolverRepository = new ImmutableBucket<IResolver>(new IResolver[10] {
new EnumerableWrapper(),
new LazyWrapper(),
new FuncWrapper(),
new MetadataWrapper(),
new KeyValueWrapper(),
new ServiceProviderResolver(),
new OptionalValueResolver(),
new DefaultValueResolver(),
parentContainerResolver,
new UnknownTypeResolver()
});
}
public ServiceContext BuildExpressionForType(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
if (typeInformation.Type == TypeCache<IDependencyResolver>.Type)
return resolutionContext.CurrentScopeParameter.AsServiceContext(null);
if (typeInformation.Type == TypeCache<IRequestContext>.Type) {
resolutionContext.RequestConfiguration.RequiresRequestContext = true;
return resolutionContext.RequestContextParameter.AsServiceContext(null);
}
if (typeInformation.IsDependency) {
if (resolutionContext.ParameterExpressions.Length > 0) {
Type type = typeInformation.Type;
int num = resolutionContext.ParameterExpressions.Length;
while (num-- > 0) {
Pair<bool, ParameterExpression>[] array = resolutionContext.ParameterExpressions[num].Where(delegate(Pair<bool, ParameterExpression> p) {
if (!(p.I2.Type == type))
return p.I2.Type.Implements(type);
return true;
}).CastToArray();
if (array.Length != 0) {
object obj = Array.Find(array, (Pair<bool, ParameterExpression> parameter) => !parameter.I1);
if (obj == null) {
Pair<bool, ParameterExpression>[] array2 = array;
obj = array2[array2.Length - 1];
}
((Pair<bool, ParameterExpression>)obj).I1 = true;
return ((Pair<bool, ParameterExpression>)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, orDefaultByRef).AsServiceContext(null);
}
ConstantExpression constantExpression = resolutionContext.ExpressionOverrides?.GetOrDefaultByValue(typeInformation.DependencyName ?? typeInformation.Type);
if (constantExpression != null)
return constantExpression.AsServiceContext(null);
ServiceRegistration serviceRegistration = resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.Current) ? resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationOrDefault(typeInformation, resolutionContext) : null;
bool flag = serviceRegistration != null && serviceRegistration.Options.IsOn(RegistrationOption.IsResolutionCallRequired);
if ((typeInformation.IsDependency && serviceRegistration != null) & flag) {
Expression target = resolutionContext.CurrentScopeParameter.ConvertTo(TypeCache<IDependencyResolver>.Type);
MethodInfo resolveMethod = Constants.ResolveMethod;
Expression[] obj2 = new Expression[4] {
typeInformation.Type.AsConstant(),
typeInformation.DependencyName.AsConstant(),
null,
null
};
HashTree<object, ConstantExpression> expressionOverrides = resolutionContext.ExpressionOverrides;
obj2[2] = (((expressionOverrides != null) ? (from c in expressionOverrides.Walk()
select c.Value).ToArray().AsConstant() : null) ?? TypeCache.EmptyArray<object>().AsConstant());
obj2[3] = resolutionContext.ResolutionBehavior.AsConstant();
return target.CallMethod(resolveMethod, obj2).ConvertTo(typeInformation.Type).AsServiceContext(serviceRegistration);
}
if (serviceRegistration == null)
return BuildExpressionUsingWrappersOrResolvers(resolutionContext, typeInformation);
return BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation);
}
public IEnumerable<ServiceContext> BuildExpressionsForEnumerableRequest(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
IEnumerable<ServiceRegistration> enumerable = resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.Current) ? resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationsOrDefault(typeInformation, resolutionContext) : null;
if (enumerable == null)
return BuildEnumerableExpressionUsingWrappersOrResolvers(resolutionContext, typeInformation);
IEnumerable<ServiceContext> enumerable2 = enumerable.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, orDefaultByRef).AsServiceContext(registration);
});
if (!parentContainerResolver.CanUseForResolution(typeInformation, resolutionContext))
return enumerable2;
IEnumerable<ServiceContext> expressionsForEnumerableRequest = parentContainerResolver.GetExpressionsForEnumerableRequest(this, typeInformation, resolutionContext);
return enumerable2.Concat(expressionsForEnumerableRequest);
}
public ServiceContext BuildExpressionForRegistration(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)
{
OpenGenericRegistration openGenericRegistration = serviceRegistration as OpenGenericRegistration;
if (openGenericRegistration != null) {
Type requestedType = serviceRegistration.ImplementationType.MakeGenericType(typeInformation.Type.GetGenericArguments());
serviceRegistration = openGenericRegistration.ProduceClosedRegistration(requestedType);
}
IContainerContext decoratorContext = resolutionContext.RequestInitiatorResolutionBehavior.Has(ResolutionBehavior.Current) ? resolutionContext.RequestInitiatorContainerContext : resolutionContext.RequestInitiatorContainerContext.ParentContext;
IEnumerable<ServiceRegistration> enumerable = (resolutionContext.RequestInitiatorResolutionBehavior.Has(ResolutionBehavior.Parent) || resolutionContext.RequestInitiatorResolutionBehavior.Has(ResolutionBehavior.ParentDependency)) ? CollectDecorators(serviceRegistration.ImplementationType, typeInformation, resolutionContext, decoratorContext) : SearchAndFilterDecorators(serviceRegistration.ImplementationType, typeInformation, resolutionContext, decoratorContext);
if (enumerable == null)
return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, typeInformation, null).AsServiceContext(serviceRegistration);
Stashbox.Utils.Data.Stack<ServiceRegistration> stack = enumerable.AsStack();
stack.PushBack(serviceRegistration);
return BuildExpressionForDecorator(stack.Front(), resolutionContext.BeginDecoratingContext(typeInformation.Type, stack), typeInformation, stack).AsServiceContext(serviceRegistration);
}
public bool IsTypeResolvable(ResolutionContext resolutionContext, TypeInformation typeInformation)
{
if (typeInformation.Type.IsGenericTypeDefinition)
return false;
if (typeInformation.Type == TypeCache<IDependencyResolver>.Type || typeInformation.Type == TypeCache<IServiceProvider>.Type || typeInformation.Type == TypeCache<IRequestContext>.Type)
return true;
if (resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(typeInformation.Type, typeInformation.DependencyName, true) || IsWrappedTypeRegistered(typeInformation, resolutionContext))
return true;
if (resolutionContext.ExpressionOverrides?.GetOrDefaultByValue(typeInformation.DependencyName ?? typeInformation.Type) == 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.Type, out Type unWrappedType)) {
TypeInformation typeInformation2 = typeInformation.Clone(unWrappedType, null, null);
return enumerableWrapper2.WrapExpression(typeInformation, typeInformation2, BuildExpressionsForEnumerableRequest(resolutionContext, typeInformation2)).AsServiceContext(null);
}
}
IServiceWrapper serviceWrapper = resolver as IServiceWrapper;
if (serviceWrapper != null) {
IServiceWrapper serviceWrapper2 = serviceWrapper;
if (serviceWrapper2.TryUnWrap(typeInformation.Type, out Type unWrappedType2)) {
TypeInformation typeInformation3 = typeInformation.Clone(unWrappedType2, null, null);
ServiceContext serviceContext = BuildExpressionForType(resolutionContext, typeInformation3);
if (!serviceContext.IsEmpty())
return serviceWrapper2.WrapExpression(typeInformation, typeInformation3, serviceContext).AsServiceContext(serviceContext.ServiceRegistration);
return ServiceContext.Empty;
}
}
IParameterizedWrapper parameterizedWrapper = resolver as IParameterizedWrapper;
if (parameterizedWrapper != null) {
IParameterizedWrapper parameterizedWrapper2 = parameterizedWrapper;
if (parameterizedWrapper2.TryUnWrap(typeInformation.Type, out Type unWrappedType3, out IEnumerable<Type> parameterTypes)) {
TypeInformation typeInformation4 = typeInformation.Clone(unWrappedType3, null, null);
ParameterExpression[] parameterExpressions = (from p in parameterTypes
select p.AsParameter(null)).CastToArray();
ServiceContext serviceContext2 = BuildExpressionForType(resolutionContext.BeginContextWithFunctionParameters(parameterExpressions), typeInformation4);
if (!serviceContext2.IsEmpty())
return parameterizedWrapper2.WrapExpression(typeInformation, typeInformation4, serviceContext2, parameterExpressions).AsServiceContext(serviceContext2.ServiceRegistration);
return ServiceContext.Empty;
}
}
IMetadataWrapper metadataWrapper = resolver as IMetadataWrapper;
if (metadataWrapper != null) {
IMetadataWrapper metadataWrapper2 = metadataWrapper;
if (metadataWrapper2.TryUnWrap(typeInformation.Type, out Type unWrappedType4, out Type metadataType)) {
TypeInformation typeInformation5 = typeInformation.Clone(unWrappedType4, null, metadataType);
ServiceContext serviceContext3 = BuildExpressionForType(resolutionContext, typeInformation5);
if (!serviceContext3.IsEmpty())
return metadataWrapper2.WrapExpression(typeInformation, typeInformation5, serviceContext3).AsServiceContext(serviceContext3.ServiceRegistration);
return ServiceContext.Empty;
}
}
}
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.Type, out Type unWrappedType)) {
TypeInformation unwrappedTypeInformation = typeInformation.Clone(unWrappedType, null, null);
return from serviceContext in BuildExpressionsForEnumerableRequest(resolutionContext, unwrappedTypeInformation)
select serviceWrapper2.WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext).AsServiceContext(serviceContext.ServiceRegistration);
}
}
IParameterizedWrapper parameterizedWrapper = resolver2 as IParameterizedWrapper;
if (parameterizedWrapper != null) {
IParameterizedWrapper parameterizedWrapper2 = parameterizedWrapper;
if (parameterizedWrapper2.TryUnWrap(typeInformation.Type, out Type unWrappedType2, out IEnumerable<Type> parameterTypes)) {
TypeInformation unwrappedTypeInformation2 = typeInformation.Clone(unWrappedType2, null, null);
ParameterExpression[] parameterExpressions = (from p in parameterTypes
select p.AsParameter(null)).CastToArray();
return from serviceContext in BuildExpressionsForEnumerableRequest(resolutionContext.BeginContextWithFunctionParameters(parameterExpressions), unwrappedTypeInformation2)
select parameterizedWrapper2.WrapExpression(typeInformation, unwrappedTypeInformation2, serviceContext, parameterExpressions).AsServiceContext(serviceContext.ServiceRegistration);
}
}
IMetadataWrapper metadataWrapper = resolver2 as IMetadataWrapper;
if (metadataWrapper != null) {
IMetadataWrapper metadataWrapper2 = metadataWrapper;
if (metadataWrapper2.TryUnWrap(typeInformation.Type, out Type unWrappedType3, out Type metadataType)) {
TypeInformation unwrappedTypeInformation3 = typeInformation.Clone(unWrappedType3, null, metadataType);
return from serviceContext in BuildExpressionsForEnumerableRequest(resolutionContext, unwrappedTypeInformation3)
select metadataWrapper2.WrapExpression(typeInformation, unwrappedTypeInformation3, serviceContext).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 ServiceContext.Empty;
}
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 TypeCache.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.Type, out Type unWrappedType)) {
IServiceWrapper serviceWrapper = resolver as IServiceWrapper;
Type unWrappedType2;
if (serviceWrapper == null || !serviceWrapper.TryUnWrap(typeInformation.Type, out unWrappedType2) || !resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(unWrappedType2, typeInformation.DependencyName, true)) {
IParameterizedWrapper parameterizedWrapper = resolver as IParameterizedWrapper;
Type unWrappedType3;
if (parameterizedWrapper == null || !parameterizedWrapper.TryUnWrap(typeInformation.Type, out unWrappedType3, out IEnumerable<Type> _) || !resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(unWrappedType3, typeInformation.DependencyName, true)) {
IMetadataWrapper metadataWrapper = resolver as IMetadataWrapper;
Type unWrappedType4;
if (metadataWrapper == null || !metadataWrapper.TryUnWrap(typeInformation.Type, out unWrappedType4, out unWrappedType) || !resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(unWrappedType4, 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;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
private IEnumerable<ServiceRegistration> CollectDecorators(Type implementationType, TypeInformation typeInformation, ResolutionContext resolutionContext, [System.Runtime.CompilerServices.Nullable(2)] IContainerContext decoratorContext)
{
if (decoratorContext == null)
return null;
IEnumerable<ServiceRegistration> enumerable = CollectDecorators(implementationType, typeInformation, resolutionContext, decoratorContext.ParentContext);
if (enumerable == null)
return SearchAndFilterDecorators(implementationType, typeInformation, resolutionContext, decoratorContext);
IEnumerable<ServiceRegistration> enumerable2 = SearchAndFilterDecorators(implementationType, typeInformation, resolutionContext, decoratorContext);
if (enumerable2 != null)
return enumerable.Concat(enumerable2);
return enumerable;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
private IEnumerable<ServiceRegistration> SearchAndFilterDecorators(Type implementationType, TypeInformation typeInformation, ResolutionContext resolutionContext, [System.Runtime.CompilerServices.Nullable(2)] IContainerContext decoratorContext)
{
IEnumerable<ServiceRegistration> enumerable = decoratorContext?.DecoratorRepository.GetDecoratorsOrDefault(implementationType, typeInformation, resolutionContext);
if (enumerable == null)
return null;
ServiceRegistration[] array = enumerable.Where(delegate(ServiceRegistration d) {
Type[] source = d.ImplementationType.GetPossibleDependencyTypes().ToArray();
if (!((IEnumerable<Type>)source).Any((Func<Type, bool>)implementationType.Implements))
return source.Any(delegate(Type t) {
if (TryUnwrapTypeFrom(t, out Type unwrapped))
return implementationType.Implements(unwrapped);
return false;
});
return true;
}).ToArray();
if (array.Length != 0)
return array;
return null;
}
private bool TryUnwrapTypeFrom(Type wrapped, out Type unwrapped)
{
int length = resolverRepository.Length;
int num = 0;
while (num < length) {
IResolver resolver = resolverRepository[num];
IEnumerableWrapper enumerableWrapper = resolver as IEnumerableWrapper;
if (enumerableWrapper == null || !enumerableWrapper.TryUnWrap(wrapped, out unwrapped)) {
IServiceWrapper serviceWrapper = resolver as IServiceWrapper;
if (serviceWrapper == null || !serviceWrapper.TryUnWrap(wrapped, out unwrapped)) {
IParameterizedWrapper parameterizedWrapper = resolver as IParameterizedWrapper;
if (parameterizedWrapper == null || !parameterizedWrapper.TryUnWrap(wrapped, out unwrapped, out IEnumerable<Type> _)) {
IMetadataWrapper metadataWrapper = resolver as IMetadataWrapper;
if (metadataWrapper == null || !metadataWrapper.TryUnWrap(wrapped, out unwrapped, out Type _)) {
num++;
continue;
}
}
}
}
return true;
}
unwrapped = TypeCache.EmptyType;
return false;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static Expression BuildExpressionForDecorator(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation, Stashbox.Utils.Data.Stack<ServiceRegistration> decorators)
{
OpenGenericRegistration openGenericRegistration = serviceRegistration as OpenGenericRegistration;
if (openGenericRegistration != null) {
Type requestedType = serviceRegistration.ImplementationType.MakeGenericType(typeInformation.Type.GetGenericArguments());
serviceRegistration = openGenericRegistration.ProduceClosedRegistration(requestedType);
}
return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, typeInformation, decorators.PeekBack()?.Lifetime);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static Expression BuildExpressionAndApplyLifetime(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation, [System.Runtime.CompilerServices.Nullable(2)] LifetimeDescriptor secondaryLifetimeDescriptor = null)
{
LifetimeDescriptor lifetimeDescriptor = (secondaryLifetimeDescriptor != null && serviceRegistration.Lifetime is EmptyLifetime) ? secondaryLifetimeDescriptor : serviceRegistration.Lifetime;
Expression expression = (!IsOutputLifetimeManageable(serviceRegistration)) ? ExpressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation) : lifetimeDescriptor.ApplyLifetime(serviceRegistration, resolutionContext, typeInformation);
if (!(typeInformation.Type != expression?.Type))
return expression;
if (expression == null)
return null;
return expression.ConvertTo(typeInformation.Type);
}
private static bool IsOutputLifetimeManageable(ServiceRegistration serviceRegistration)
{
if (!(serviceRegistration is OpenGenericRegistration))
return !serviceRegistration.IsInstance();
return false;
}
}
}