Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="2.9.0-preview-517" />

 LazyResolver

using Stashbox.Entity; using Stashbox.Registration; using Stashbox.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace Stashbox.Resolution.Resolvers { internal class LazyResolver : IMultiServiceResolver, IResolver { private static readonly MethodInfo DelegateCacheMethod = typeof(LazyResolver).GetSingleMethod("CreateLazyDelegate", true); public Expression GetExpression(IContainerContext containerContext, IResolutionStrategy resolutionStrategy, TypeInformation typeInfo, ResolutionContext resolutionContext) { TypeInformation typeInformation = typeInfo.Clone(typeInfo.Type.GetGenericArguments()[0]); Type type = Constants.FuncType.MakeGenericType(typeInformation.Type); ConstructorInfo constructor = typeInfo.Type.GetConstructor(type); IServiceRegistration registrationOrDefault = containerContext.RegistrationRepository.GetRegistrationOrDefault(typeInformation, resolutionContext); if (registrationOrDefault != null) { if (containerContext.ContainerConfiguration.CircularDependenciesWithLazyEnabled) return CreateLazyExpressionCall(containerContext, registrationOrDefault, typeInformation.Type, constructor, resolutionContext); return constructor.MakeNew(registrationOrDefault.GetExpression(containerContext, resolutionContext, typeInformation.Type).AsLambda(Array.Empty<ParameterExpression>())); } Expression expression = resolutionStrategy.BuildResolutionExpression(containerContext, resolutionContext, typeInformation, null, false); if (expression != null) return constructor.MakeNew(expression.AsLambda(Array.Empty<ParameterExpression>())); return null; } public Expression[] GetAllExpressions(IContainerContext containerContext, IResolutionStrategy resolutionStrategy, TypeInformation typeInfo, ResolutionContext resolutionContext) { TypeInformation typeInformation = typeInfo.Clone(typeInfo.Type.GetGenericArguments()[0]); Type type = Constants.FuncType.MakeGenericType(typeInformation.Type); ConstructorInfo constructor = typeInfo.Type.GetConstructor(type); IEnumerable<KeyValue<object, IServiceRegistration>> registrationsOrDefault = containerContext.RegistrationRepository.GetRegistrationsOrDefault(typeInformation.Type, resolutionContext); KeyValue<object, IServiceRegistration>[] array = (registrationsOrDefault != null) ? registrationsOrDefault.CastToArray() : null; if (array != null) { int num = array.Length; Expression[] array2 = new Expression[num]; for (int i = 0; i < num; i++) { if (!containerContext.ContainerConfiguration.CircularDependenciesWithLazyEnabled) array2[i] = constructor.MakeNew(array[i].Value.GetExpression(containerContext, resolutionContext, typeInformation.Type).AsLambda(Array.Empty<ParameterExpression>())); else array2[i] = CreateLazyExpressionCall(containerContext, array[i].Value, typeInformation.Type, constructor, resolutionContext); } return array2; } Expression[] array3 = resolutionStrategy.BuildAllResolutionExpressions(containerContext, resolutionContext, typeInformation); if (array3 == null) return null; int num2 = array3.Length; Expression[] array4 = new Expression[num2]; for (int j = 0; j < num2; j++) { array4[j] = constructor.MakeNew(array3[j].AsLambda(Array.Empty<ParameterExpression>())); } return array4; } private static Expression CreateLazyExpressionCall(IContainerContext containerContext, IServiceRegistration serviceRegistration, Type type, ConstructorInfo constructor, ResolutionContext resolutionContext) { Expression[] array = (resolutionContext.ParameterExpressions != null) ? new Expression[resolutionContext.ParameterExpressions.Sum((ArrayStoreKeyed<bool, ParameterExpression> x) => x.Length)] : new Expression[0]; if (resolutionContext.ParameterExpressions != null) { int num = 0; for (int i = 0; i < resolutionContext.ParameterExpressions.Length; i++) { for (int j = 0; j < resolutionContext.ParameterExpressions[i].Length; j++) { array[num++] = resolutionContext.ParameterExpressions[i][j].ConvertTo(typeof(object)); } } } MethodCallExpression expression = DelegateCacheMethod.CallStaticMethod(containerContext.AsConstant(), serviceRegistration.AsConstant(), resolutionContext.AsConstant(), type.AsConstant(), typeof(object).InitNewArray(array)); return constructor.MakeNew(expression.ConvertTo(type).AsLambda(Array.Empty<ParameterExpression>())); } public bool CanUseForResolution(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) { if (typeInfo.Type.IsClosedGenericType()) return typeInfo.Type.GetGenericTypeDefinition() == typeof(Lazy<>); return false; } private static object CreateLazyDelegate(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type type, object[] arguments) { return serviceRegistration.GetExpression(containerContext, resolutionContext, type).AsLambda(resolutionContext.ParameterExpressions.SelectMany((ArrayStoreKeyed<bool, ParameterExpression> x) => x)).CompileDynamicDelegate(resolutionContext, containerContext.ContainerConfiguration)(resolutionContext.ResolutionScope).DynamicInvoke(arguments); } } }