private Expression CreateResolveExpressionRecursively(TypeKey requestedTypeKey, Registration registration, DependencyOverrides dependencyOverrides, DependencyInjectionContainer container) { // Check if the lifetime of the registration would need to create a new instance. // If not, then we do not need to create a construction expression Expression resolveContextExpression; if (registration.Lifetime.IsCreatingNewInstances == false) { // If the lifetime can be resolved during compilation, then create a resolve context and immediately // call ResolveInstance to compile a constant reference to the instance into the resolve method if (registration.Lifetime.CanBeResolvedDuringCompilation) { var instance = registration.Lifetime.ResolveInstance(container.Services.ResolveContextFactory.Create(container).ChangeRegistration(registration)); return(Expression.Constant(instance, requestedTypeKey.Type)); } // Else prepare the resolve context parameter with the target registration and call the ResolveInstance dynamically resolveContextExpression = Expression.Call(Constants.ResolveContextParameterExpression, Constants.ChangeRegistrationMethod, Expression.Constant(registration)); return(Expression.Convert(Expression.Call(Expression.Constant(registration.Lifetime), Constants.LifetimeResolveInstanceMethod, resolveContextExpression), requestedTypeKey.Type)); } // Else we need to create a construction expression that instantiates the target type and performs any instance manipulations var resolveExpressionContext = new ResolveExpressionContext(requestedTypeKey, registration, dependencyOverrides, container); var constructionExpression = CreateConstructionExpression(resolveExpressionContext); // Check if the lifetime implements IOptimizeLifetimeExpression to avoid compiling the construction expression to a delegate if (registration.Lifetime is IOptimizeLifetimeExpression optimizeLifetimeExpression) { return(optimizeLifetimeExpression.Optimize(constructionExpression, resolveExpressionContext)); } // Compile the construction expression to a delegate so that it can be injected into the ResolveContext var compiledDelegate = constructionExpression.CompileToResolveDelegate(Constants.ResolveContextParameterExpression); var targetLifetime = resolveExpressionContext.IsResolvingGenericTypeDefinition ? registration.Lifetime.GetLifetimeInstanceForConstructedGenericType() : registration.Lifetime; // If the lifetime can be resolved during compilation, then create a resolve context and immediately // call ResolveInstance to compile a constant reference to the instance into the resolve method if (targetLifetime.CanBeResolvedDuringCompilation) { var instance = targetLifetime.ResolveInstance(container.Services.ResolveContextFactory.Create(container).ChangeResolvedType(registration, compiledDelegate)); return(Expression.Constant(instance)); } // Else create a expression that calls the target lifetime using the compiled delegate resolveContextExpression = Expression.Call(Constants.ResolveContextParameterExpression, Constants.ChangeResolvedTypeMethod, Expression.Constant(registration), Expression.Constant(compiledDelegate)); return(Expression.Convert(Expression.Call(Expression.Constant(targetLifetime), Constants.LifetimeResolveInstanceMethod, resolveContextExpression), requestedTypeKey.Type)); }
private static ConstructorInfo FindConstructorOfClosedConstructedGenericType(ResolveExpressionContext context, ConstructorInstantiationInfo instantiationInfo) { var constructors = context.ResolvedGenericRegistrationTypeInfo.DeclaredConstructors.AsReadOnlyList(); var targetConstructor = context.FindResolvedGenericMethod(instantiationInfo.ConstructorInfo, constructors); if (targetConstructor != null) { return(targetConstructor); } throw new ResolveException($"The constructor for the closed constructed generic type \"{context.RequestedType}\" that matches the generic type definition's constructor \"{instantiationInfo.ConstructorInfo}\" could not be found. This exception should actually never happen, unless there is a bug in class \"{nameof(ConstructorInstantiationInfoFactory)}\" or you messed with the .NET type system badly."); }
protected override Expression Create(ConstructorInstantiationInfo instantiationInfo, ResolveExpressionContext context, Expression[] parameterExpressions) { if (context.IsResolvingGenericTypeDefinition == false) { return(Expression.New(instantiationInfo.ConstructorInfo, parameterExpressions)); } var targetConstructor = FindConstructorOfClosedConstructedGenericType(context, instantiationInfo); return(Expression.New(targetConstructor, parameterExpressions)); }
private Expression CreateConstructionExpression(ResolveExpressionContext context) { // Create the expression that instantiates the target object var instantiationInfo = context.Registration.TypeConstructionInfo.InstantiationInfo; var parameterExpressions = ResolveDependenciesRecursivelyIfNecessary(instantiationInfo.InstantiationDependencies, context); // Use the correct factory to create the expression that instantiates the target type if (_instantiationExpressionFactories.TryGetValue(instantiationInfo.GetType(), out var instantiationExpressionFactory) == false) { throw new InvalidOperationException($"There is no instantiationExpressionFactory present for \"{instantiationInfo.GetType()}\". Please check that \"{nameof(CompiledLinqExpressionFactory)}\" is created with all necessary dependencies in \"{nameof(ContainerServices)}\"."); } var instantiationExpression = instantiationExpressionFactory.Create(instantiationInfo, context, parameterExpressions); // If there are no instance manipulations, then simply return the instantiation expression var instanceManipulations = context.Registration.TypeConstructionInfo.InstanceManipulations; if (instanceManipulations.IsNullOrEmpty()) { return(instantiationExpression); } // Else we need a block that holds the target object in a variable and performs each instance manipulation in one statement // The first statement is always the assignment of the instantiationExpression to a variable that holds the instance var instanceVariableExpression = Expression.Variable(context.InstanceType); var assignVariableExpression = Expression.Assign(instanceVariableExpression, instantiationExpression); var blockExpressions = new Expression[instanceManipulations.Count + 2]; // +2 for assignment and return statements blockExpressions[0] = assignVariableExpression; // variable assign statement // The subsequent statements hold the instance manipulations (e.g. property injection, field injection, calling methods, etc.) for (var i = 0; i < instanceManipulations.Count; i++) { var instanceManipulation = instanceManipulations[i]; parameterExpressions = ResolveDependenciesRecursivelyIfNecessary(instanceManipulation.Dependencies, context); if (_instanceManipulationExpressionFactories.TryGetValue(instanceManipulation.GetType(), out var instanceManipulationExpressionFactory) == false) { throw new InvalidOperationException($"There is no instanceManipulationExpressionFactory present for \"{instanceManipulation.GetType()}\". Please check that \"{nameof(CompiledLinqExpressionFactory)}\" is created with all necessary dependencies in \"{nameof(ContainerServices)}\"."); } blockExpressions[i + 1] = instanceManipulationExpressionFactory.Create(instanceManipulation, instanceVariableExpression, context, parameterExpressions); } blockExpressions[blockExpressions.Length - 1] = instanceVariableExpression; // Return statement return(Expression.Block(context.InstanceType, new[] { instanceVariableExpression }, blockExpressions)); }
protected abstract Expression Create(T instanceManipulation, ParameterExpression instanceVariableExpression, ResolveExpressionContext context, Expression[] parameterExpressions);
public Expression Create(InstanceManipulation instanceManipulation, ParameterExpression instanceVariableExpression, ResolveExpressionContext context, Expression[] parameterExpressions) { return(Create(instanceManipulation.MustBeOfType <T>(nameof(instanceManipulation)), instanceVariableExpression.MustNotBeNull(nameof(instanceVariableExpression)), context, parameterExpressions)); }
protected override Expression Create(FieldInjection fieldInjection, ParameterExpression instanceVariableExpression, ResolveExpressionContext context, Expression[] parameterExpressions) { parameterExpressions.MustHaveCount(1, nameof(parameterExpressions)); var targetField = fieldInjection.TargetField; if (context.IsResolvingGenericTypeDefinition) { targetField = context.ResolvedGenericRegistrationType.GetRuntimeField(targetField.Name); } return(Expression.Assign(Expression.Field(instanceVariableExpression, targetField), parameterExpressions[0])); }
protected abstract Expression Create(T instantiationInfo, ResolveExpressionContext context, Expression[] parameterExpressions);
public Expression Create(InstantiationInfo instantiationInfo, ResolveExpressionContext context, Expression[] parameterExpressions) { return(Create(instantiationInfo.MustBeOfType <T>(nameof(instantiationInfo)), context, parameterExpressions)); }
protected override Expression Create(StaticMethodInstantiationInfo instantiationInfo, ResolveExpressionContext context, Expression[] parameterExpressions) { if (instantiationInfo.TypeKey.Type.IsGenericTypeDefinition() == false) { return(Expression.Call(instantiationInfo.StaticMethod, parameterExpressions)); } if (instantiationInfo.StaticMethod.DeclaringType.IsGenericTypeDefinition()) { var closedConstructedStaticType = instantiationInfo.StaticMethod.DeclaringType.MakeGenericType(context.ResolvedGenericRegistrationTypeInfo.GenericTypeArguments); var closedConstructedMethods = closedConstructedStaticType.GetTypeInfo().GetDeclaredMethods(instantiationInfo.StaticMethod.Name).AsReadOnlyList(); var staticMethodOfClosedConstructedStaticType = context.FindResolvedGenericMethod(instantiationInfo.StaticMethod, closedConstructedMethods); if (staticMethodOfClosedConstructedStaticType != null) { return(Expression.Call(staticMethodOfClosedConstructedStaticType, parameterExpressions)); } throw new ResolveException($"The static method \"{instantiationInfo.StaticMethod}\" could not be found for the closed constructed type \"{closedConstructedStaticType}\". This exception should actually never happen, unless there is a bug in class \"{nameof(StaticMethodInstantiationInfoFactory)}\" or you messed with the .NET type system badly."); } var closedConstructedGenericMethod = instantiationInfo.StaticMethod.MakeGenericMethod(context.ResolvedGenericRegistrationTypeInfo.GenericTypeArguments); return(Expression.Call(closedConstructedGenericMethod, parameterExpressions)); }
private Expression[] ResolveDependenciesRecursivelyIfNecessary(IReadOnlyList <Dependency> dependencies, ResolveExpressionContext context) { if (dependencies.IsNullOrEmpty()) { return(null); } var resolvedDependencyExpressions = new Expression[dependencies.Count]; for (var i = 0; i < resolvedDependencyExpressions.Length; i++) { var dependency = dependencies[i]; var dependencyType = dependency.TargetType; dependencyType = context.ResolveGenericTypeParameterIfNecessary(dependencyType); dependencyType = context.ResolveOpenConstructedGenericTypeIfNecessary(dependencyType); // Check if the dependency is overridden - if yes, then resolve it via the ResolveContext parameter if (context.DependencyOverrides?.HasDependency(dependency) == true) { resolvedDependencyExpressions[i] = Expression.Convert(Expression.Call(Expression.Call(Constants.ResolveContextParameterExpression, Constants.GetDependencyOverridesProperty), Constants.GetDependencyInstanceMethod, Expression.Constant(dependency)), dependency.TargetType); continue; } resolvedDependencyExpressions[i] = CreateResolveExpressionRecursively(new TypeKey(dependencyType, dependency.TargetRegistrationName), context.Container, context.DependencyOverrides, dependency.ResolveAll); } return(resolvedDependencyExpressions); }
protected override Expression Create(DelegateInstantiationInfo instantiationInfo, ResolveExpressionContext context, Expression[] parameterExpressions) { var methodInfo = instantiationInfo.Delegate.GetMethodInfo(); return(Expression.Call(methodInfo, parameterExpressions)); }
protected override Expression Create(PropertyInjection propertyInjection, ParameterExpression instanceVariableExpression, ResolveExpressionContext context, Expression[] parameterExpressions) { var targetProperty = propertyInjection.TargetProperty; if (context.IsResolvingGenericTypeDefinition) { targetProperty = context.ResolvedGenericRegistrationType.GetRuntimeProperty(targetProperty.Name); } return(Expression.Call(instanceVariableExpression, targetProperty.SetMethod, parameterExpressions)); }