ExpressionFactory
class ExpressionFactory
using Stashbox.Registration;
using Stashbox.Resolution;
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.Expressions
{
internal class ExpressionFactory
{
private readonly MethodExpressionFactory methodExpressionBuilder;
private readonly MemberExpressionFactory memberExpressionBuilder;
public ExpressionFactory(MethodExpressionFactory methodExpressionBuilder, MemberExpressionFactory memberExpressionBuilder)
{
this.methodExpressionBuilder = methodExpressionBuilder;
this.memberExpressionBuilder = memberExpressionBuilder;
}
public Expression ConstructBuildUpExpression(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Expression instance, Type serviceType)
{
if (instance.Type != serviceRegistration.ImplementationType)
instance = instance.ConvertTo(serviceRegistration.ImplementationType);
MethodInfo[] usableMethods = serviceRegistration.ImplementationTypeInfo.GetUsableMethods();
MemberInfo[] usableMembers = serviceRegistration.ImplementationTypeInfo.GetUsableMembers(serviceRegistration.RegistrationContext, resolutionContext.CurrentContainerContext.ContainerConfiguration);
if (usableMembers.Length == 0 && usableMethods.Length == 0 && (object)serviceRegistration.RegistrationContext.Initializer == null)
return instance;
ParameterExpression parameterExpression = instance.Type.AsVariable(null);
BinaryExpression item = parameterExpression.AssignTo(instance);
ExpandableArray<Expression> expandableArray = new ExpandableArray<Expression> {
item
};
expandableArray.AddRange(memberExpressionBuilder.GetMemberExpressions(usableMembers, serviceRegistration.RegistrationContext, resolutionContext, parameterExpression));
expandableArray.AddRange(methodExpressionBuilder.CreateMethodExpressions(usableMethods, serviceRegistration.RegistrationContext, resolutionContext, parameterExpression));
if ((object)serviceRegistration.RegistrationContext.Initializer != null)
expandableArray.Add(serviceRegistration.RegistrationContext.Initializer.AsConstant().CallMethod(serviceRegistration.RegistrationContext.Initializer.GetType().GetSingleMethod("Invoke"), parameterExpression, resolutionContext.CurrentScopeParameter.ConvertTo(Constants.ResolverType)));
expandableArray.Add((parameterExpression.Type != serviceType) ? parameterExpression.ConvertTo(serviceType) : parameterExpression);
return expandableArray.AsBlock(parameterExpression);
}
public Expression ConstructBuildUpExpression(ResolutionContext resolutionContext, Expression instance, Type serviceType)
{
RegistrationContext empty = RegistrationContext.Empty;
TypeInfo typeInfo = instance.Type.GetTypeInfo();
MethodInfo[] usableMethods = typeInfo.GetUsableMethods();
MemberInfo[] usableMembers = typeInfo.GetUsableMembers(empty, resolutionContext.CurrentContainerContext.ContainerConfiguration);
if (usableMembers.Length == 0 && usableMethods.Length == 0)
return instance;
ParameterExpression parameterExpression = instance.Type.AsVariable(null);
BinaryExpression item = parameterExpression.AssignTo(instance);
ExpandableArray<Expression> expandableArray = new ExpandableArray<Expression>();
expandableArray.Add(item);
expandableArray.AddRange(memberExpressionBuilder.GetMemberExpressions(usableMembers, empty, resolutionContext, parameterExpression));
expandableArray.AddRange(methodExpressionBuilder.CreateMethodExpressions(usableMethods, empty, resolutionContext, instance));
expandableArray.Add((parameterExpression.Type != serviceType) ? parameterExpression.ConvertTo(serviceType) : parameterExpression);
return expandableArray.AsBlock(parameterExpression);
}
public Expression ConstructExpression(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext)
{
IEnumerable<ConstructorInfo> usableConstructors = serviceRegistration.ImplementationTypeInfo.GetUsableConstructors();
MethodInfo[] usableMethods = serviceRegistration.ImplementationTypeInfo.GetUsableMethods();
MemberInfo[] usableMembers = serviceRegistration.ImplementationTypeInfo.GetUsableMembers(serviceRegistration.RegistrationContext, resolutionContext.CurrentContainerContext.ContainerConfiguration);
Expression expression = CreateInitExpression(serviceRegistration.RegistrationContext, resolutionContext, usableConstructors);
if (expression == null)
return null;
if (usableMembers.Length != 0)
expression = expression.InitMembers(memberExpressionBuilder.GetMemberBindings(usableMembers, serviceRegistration.RegistrationContext, resolutionContext));
if (usableMethods.Length == 0 && (object)serviceRegistration.RegistrationContext.Initializer == null)
return expression;
ParameterExpression parameterExpression = expression.Type.AsVariable(null);
BinaryExpression item = parameterExpression.AssignTo(expression);
ExpandableArray<Expression> expandableArray = new ExpandableArray<Expression> {
item
};
expandableArray.AddRange(methodExpressionBuilder.CreateMethodExpressions(usableMethods, serviceRegistration.RegistrationContext, resolutionContext, parameterExpression));
if ((object)serviceRegistration.RegistrationContext.Initializer != null)
expandableArray.Add(serviceRegistration.RegistrationContext.Initializer.AsConstant().CallMethod(serviceRegistration.RegistrationContext.Initializer.GetType().GetSingleMethod("Invoke"), parameterExpression, resolutionContext.CurrentScopeParameter.ConvertTo(Constants.ResolverType)));
expandableArray.Add(parameterExpression);
return expandableArray.AsBlock(parameterExpression);
}
public Expression ConstructExpression(ResolutionContext resolutionContext, Type serviceType)
{
RegistrationContext empty = RegistrationContext.Empty;
TypeInfo typeInfo = serviceType.GetTypeInfo();
MethodInfo[] usableMethods = typeInfo.GetUsableMethods();
MemberInfo[] usableMembers = typeInfo.GetUsableMembers(empty, resolutionContext.CurrentContainerContext.ContainerConfiguration);
Expression[] parameterExpressions;
Expression expression = methodExpressionBuilder.SelectConstructor(empty, resolutionContext, typeInfo.DeclaredConstructors.CastToArray(), out parameterExpressions).MakeNew(parameterExpressions);
if (usableMembers.Length != 0)
expression = expression.InitMembers(memberExpressionBuilder.GetMemberBindings(usableMembers, empty, resolutionContext));
if (usableMethods.Length == 0)
return expression;
ParameterExpression parameterExpression = expression.Type.AsVariable(null);
BinaryExpression item = parameterExpression.AssignTo(expression);
ExpandableArray<Expression> expandableArray = new ExpandableArray<Expression>();
expandableArray.Add(item);
expandableArray.AddRange(methodExpressionBuilder.CreateMethodExpressions(usableMethods, empty, resolutionContext, parameterExpression));
expandableArray.Add(parameterExpression);
return expandableArray.AsBlock(parameterExpression);
}
private Expression CreateInitExpression(RegistrationContext registrationContext, ResolutionContext resolutionContext, IEnumerable<ConstructorInfo> constructors)
{
if (registrationContext.SelectedConstructor != (ConstructorInfo)null) {
if (registrationContext.ConstructorArguments != null)
return registrationContext.SelectedConstructor.MakeNew(registrationContext.ConstructorArguments.Select(Expression.Constant));
return registrationContext.SelectedConstructor.MakeNew(methodExpressionBuilder.CreateParameterExpressionsForMethod(registrationContext, resolutionContext, registrationContext.SelectedConstructor));
}
constructors = (registrationContext.ConstructorSelectionRule ?? resolutionContext.CurrentContainerContext.ContainerConfiguration.ConstructorSelectionRule)(constructors);
Expression[] parameterExpressions;
ConstructorInfo constructorInfo = methodExpressionBuilder.SelectConstructor(registrationContext, resolutionContext, constructors.CastToArray(), out parameterExpressions);
if ((object)constructorInfo == null)
return null;
return constructorInfo.MakeNew(parameterExpressions);
}
}
}