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, IWrapper
{
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)
{
return IsLazy(typeInfo.Type);
}
public bool TryUnWrap(TypeInformation typeInfo, out IEnumerable<Type> unWrappedTypes)
{
if (!IsLazy(typeInfo.Type)) {
unWrappedTypes = null;
return false;
}
unWrappedTypes = new Type[1] {
typeInfo.Type.GetGenericArguments()[0]
};
return true;
}
private Expression GetLazyFuncExpression(TypeInformation argumentType, ResolutionContext resolutionContext, IResolutionStrategy resolutionStrategy)
{
if (!resolutionContext.CurrentContainerContext.ContainerConfiguration.CircularDependenciesWithLazyEnabled)
return resolutionStrategy.BuildExpressionForType(resolutionContext, argumentType);
return resolutionContext.CurrentScopeParameter.CallMethod(Constants.ResolveMethod, 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);
}
private static bool IsLazy(Type type)
{
if (type.IsClosedGenericType())
return type.GetGenericTypeDefinition() == typeof(Lazy<>);
return false;
}
}
}