LazyResolver
using Stashbox.Utils;
using Stashbox.Utils.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Stashbox.Resolution.Resolvers
{
internal class LazyResolver : IEnumerableSupportedResolver, IResolver
{
private static readonly MethodInfo ResolveMethodInfo = Constants.ResolverType.GetMethodByArguments("Resolve", typeof(Type), Constants.ObjectType, typeof(bool), typeof(object[]));
public Expression GetExpression(IResolutionStrategy resolutionStrategy, TypeInformation typeInfo, ResolutionContext resolutionContext)
{
TypeInformation typeInformation = typeInfo.CloneForType(typeInfo.Type.GetGenericArguments()[0]);
Type type = Constants.FuncType.MakeGenericType(typeInformation.Type);
ConstructorInfo constructor = typeInfo.Type.GetConstructor(type);
Expression lazyFuncExpression = GetLazyFuncExpression(typeInformation, resolutionContext, resolutionStrategy);
if (lazyFuncExpression != null)
return constructor.MakeNew(lazyFuncExpression.AsLambda(Array.Empty<ParameterExpression>()));
return null;
}
public IEnumerable<Expression> GetExpressionsForEnumerableRequest(IResolutionStrategy resolutionStrategy, TypeInformation typeInfo, ResolutionContext resolutionContext)
{
TypeInformation typeInformation = typeInfo.CloneForType(typeInfo.Type.GetGenericArguments()[0]);
Type type = Constants.FuncType.MakeGenericType(typeInformation.Type);
ConstructorInfo lazyConstructor = typeInfo.Type.GetConstructor(type);
IEnumerable<Expression> enumerable = resolutionStrategy.BuildExpressionsForEnumerableRequest(resolutionContext, typeInformation);
if (enumerable == null)
return null;
return from e in enumerable
select lazyConstructor.MakeNew(e.AsLambda(Array.Empty<ParameterExpression>()));
}
public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
if (typeInfo.Type.IsClosedGenericType())
return typeInfo.Type.GetGenericTypeDefinition() == typeof(Lazy<>);
return false;
}
private Expression GetLazyFuncExpression(TypeInformation argumentType, ResolutionContext resolutionContext, IResolutionStrategy resolutionStrategy)
{
if (!resolutionContext.CurrentContainerContext.ContainerConfiguration.CircularDependenciesWithLazyEnabled)
return resolutionStrategy.BuildExpressionForType(resolutionContext, argumentType);
return resolutionContext.CurrentScopeParameter.CallMethod(ResolveMethodInfo, argumentType.Type.AsConstant(), argumentType.DependencyName.AsConstant(), false.AsConstant(), Constants.ObjectType.InitNewArray(resolutionContext.ParameterExpressions.SelectMany((Pair<bool, ParameterExpression>[] x) => from i in x
select i.I2.ConvertTo(Constants.ObjectType)))).ConvertTo(argumentType.Type);
}
}
}