Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="5.17.0" />

 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 != null && typeInformation.HasDependencyNameAttribute && typeInformation.Parent != null) return typeInformation.Parent.DependencyName.AsConstant().ConvertTo(typeInformation.Type).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); } ExpandableArray<Override> expandableArray = resolutionContext.ExpressionOverrides?.GetOrDefault(typeInformation.Type); if (expandableArray != null) { Override override = (typeInformation.DependencyName != null) ? expandableArray.LastOrDefault((Override e) => typeInformation.DependencyName.Equals(e.DependencyName)) : expandableArray.LastOrDefault(); if (override != null) return override.Instance.AsConstant().AsServiceContext(null); } ServiceRegistration serviceRegistration = resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.Current) ? resolutionContext.CurrentContainerContext.RegistrationRepository.GetRegistrationOrDefault(typeInformation, resolutionContext) : null; if (serviceRegistration != null && serviceRegistration.Options.IsOn(RegistrationOption.IsResolutionCallRequired) && typeInformation.IsDependency && serviceRegistration != null) { 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<Type, ExpandableArray<Override>> expressionOverrides = resolutionContext.ExpressionOverrides; obj2[2] = (((expressionOverrides != null) ? expressionOverrides.Walk().SelectMany((ExpandableArray<Override> c) => from ov in c select (ov)).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 (resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.PreferEnumerableInCurrent) && !resolutionContext.IsInParentContext) return enumerable2; if (!parentContainerResolver.CanUseForResolution(typeInformation, resolutionContext)) return enumerable2; return parentContainerResolver.GetExpressionsForEnumerableRequest(this, typeInformation, resolutionContext).Concat(enumerable2); } 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; ExpandableArray<Override> expandableArray = resolutionContext.ExpressionOverrides?.GetOrDefault(typeInformation.Type); if (expandableArray == null) return CanLookupService(typeInformation, resolutionContext); if (typeInformation.DependencyName != null) return expandableArray.LastOrDefault((Override exp) => exp.DependencyName == typeInformation.DependencyName) != null; 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); IEnumerable<ServiceContext> enumerable = BuildExpressionsForEnumerableRequest(resolutionContext, typeInformation2); if (resolutionContext.CurrentContainerContext.ContainerConfiguration.ExceptionOverEmptyCollectionEnabled && !typeInformation.Type.MapsToGenericTypeDefinition(TypeCache.EnumerableType) && enumerable == TypeCache.EmptyArray<ServiceContext>()) return ServiceContext.Empty; return enumerableWrapper2.WrapExpression(typeInformation, typeInformation2, enumerable).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; Type unWrappedType; if (enumerableWrapper == null || ((!enumerableWrapper.TryUnWrap(typeInformation.Type, out unWrappedType) || resolutionContext.CurrentContainerContext.ContainerConfiguration.ExceptionOverEmptyCollectionEnabled) && !typeInformation.Type.MapsToGenericTypeDefinition(TypeCache.EnumerableType) && !resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(unWrappedType, typeInformation.DependencyName, true))) { 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 Type _) || !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) || lifetimeDescriptor is EmptyLifetime) ? 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; } } }