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);
}
}
}