Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="3.1.2" />

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