Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="4.0.0-preview-662" />

 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 ImmutableBucket<IResolver> resolverRepository = ImmutableBucket<IResolver>.Empty; private ImmutableBucket<IResolver> lastChanceResolverRepository = ImmutableBucket<IResolver>.Empty; public Expression BuildExpressionForType(ResolutionContext resolutionContext, TypeInformation typeInformation) { if (typeInformation.Type == Constants.ResolverType || typeInformation.Type == Constants.ServiceProviderType) return resolutionContext.CurrentScopeParameter; if (typeInformation.Type == Constants.ResolutionContextType) return resolutionContext.AsConstant(); 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; } } } 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); } ConstantExpression expressionOverrideOrDefault = resolutionContext.GetExpressionOverrideOrDefault(typeInformation.Type, typeInformation.DependencyName); if (expressionOverrideOrDefault != null) return expressionOverrideOrDefault; ServiceRegistration registrationOrDefault = resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationOrDefault(typeInformation, resolutionContext); resolutionContext.IsTopRequest = false; 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> orDefaultByRef = resolutionContext.RemainingDecorators.GetOrDefaultByRef(typeInformation.Type); if (orDefaultByRef == null || orDefaultByRef.Length == 0) return BuildExpressionForRegistration(reg, resolutionContext, typeInformation); orDefaultByRef.ReplaceBack(reg); return BuildExpressionForDecorator(orDefaultByRef.Front(), resolutionContext.BeginDecoratingContext(typeInformation.Type, orDefaultByRef), typeInformation.Type, orDefaultByRef); }); } 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.Front(), resolutionContext.BeginDecoratingContext(type, stack), type, stack); } private 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(serviceRegistration, resolutionContext, requestedType); } private static bool IsOutputLifetimeManageable(ServiceRegistration serviceRegistration) { if (serviceRegistration.RegistrationType != RegistrationType.OpenGeneric) return serviceRegistration.RegistrationType != RegistrationType.Instance; return false; } } }