Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="5.0.0-preview-719" />

 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.AsContext(null); if (typeInformation.Type == Constants.RequestContextType) return resolutionContext.RequestContextParameter.AsContext(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.AsContext(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).AsContext(null); } ConstantExpression expressionOverrideOrDefault = resolutionContext.GetExpressionOverrideOrDefault(typeInformation.Type, typeInformation.DependencyName); if (expressionOverrideOrDefault != null) return expressionOverrideOrDefault.AsContext(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).AsContext(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).AsContext(serviceRegistration); Stashbox.Utils.Data.Stack<ServiceRegistration> stack = decoratorsOrDefault.AsStack(); stack.PushBack(serviceRegistration); return BuildExpressionForDecorator(stack.Front(), resolutionContext.BeginDecoratingContext(type, stack), type, stack).AsContext(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)).AsContext(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).AsContext(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).AsContext(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).AsContext(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).AsContext(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; } } }