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;
typeInformation.Type = 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;
typeInformation.Type = typeInfo.Type.GetGenericArguments()[0];
Type type = Constants.FuncType.MakeGenericType(typeInformation.Type);
ConstructorInfo constructor = typeInfo.Type.GetConstructor(type);
IEnumerable<IServiceRegistration> registrationsOrDefault = containerContext.RegistrationRepository.GetRegistrationsOrDefault(typeInformation, resolutionContext);
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].GetExpression(containerContext, resolutionContext, typeInformation.Type).AsLambda(Array.Empty<ParameterExpression>()));
else
array2[i] = CreateLazyExpressionCall(containerContext, array[i], 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((KeyValue<bool, ParameterExpression>[] x) => x.Length)] : new Expression[0];
if (resolutionContext.ParameterExpressions != null) {
int num = 0;
for (int i = 0; i < resolutionContext.ParameterExpressions.Count; i++) {
for (int j = 0; j < resolutionContext.ParameterExpressions[i].Length; j++) {
array[num++] = resolutionContext.ParameterExpressions[i][j].Value.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((KeyValue<bool, ParameterExpression>[] x) => from i in x
select i.Value)).CompileDynamicDelegate(resolutionContext, containerContext.ContainerConfiguration)(resolutionContext.ResolutionScope).DynamicInvoke(arguments);
}
}
}