public ResolveExpressionContext(TypeKey requestedTypeKey, Registration registration, DependencyOverrides dependencyOverrides, DependencyInjectionContainer container) { RequestedTypeKey = requestedTypeKey.MustNotBeEmpty(nameof(requestedTypeKey)); Registration = registration.MustNotBeNull(nameof(registration)); DependencyOverrides = dependencyOverrides; Container = container.MustNotBeNull(nameof(container)); RegistrationTypeInfo = registration.TypeKey.Type.GetTypeInfo(); ResolvedGenericRegistrationType = null; ResolvedGenericRegistrationTypeInfo = null; // ReSharper disable once PossibleNullReferenceException if (RegistrationTypeInfo.IsGenericTypeDefinition == false) { return; } try { ResolvedGenericRegistrationType = registration.TargetType.MakeGenericType(RequestedType.GenericTypeArguments); ResolvedGenericRegistrationTypeInfo = ResolvedGenericRegistrationType.GetTypeInfo(); } catch (Exception exception) { throw new ResolveException($"Could not resolve a concrete instance of the generic type definition \"{RegistrationType}\" using the type \"{RequestedType}\".", exception); } }
public ResolveContext ChangeInitialContext(DependencyInjectionContainer container, DependencyOverrides dependencyOverrides) { _registration = null; _createInstance = null; _perResolveInstances?.Clear(); _container = container.MustNotBeNull(nameof(container)); _dependencyOverrides = dependencyOverrides; return(this); }
public ResolveDelegate Create(Registration registration, DependencyOverrides dependencyOverrides, DependencyInjectionContainer container) { registration.MustNotBeNull(nameof(registration)); container.MustNotBeNull(nameof(container)); var resolveExpression = CreateResolveExpressionRecursively(registration.TypeKey, registration, dependencyOverrides, container); return(resolveExpression.CompileToResolveDelegate(Constants.ResolveContextParameterExpression)); }
public ResolveDelegate Create(TypeKey typeKey, DependencyOverrides dependencyOverrides, DependencyInjectionContainer container) { typeKey.MustNotBeEmpty(nameof(typeKey)); container.MustNotBeNull(nameof(container)); var resolveExpression = CreateResolveExpressionRecursively(typeKey, container, dependencyOverrides); return(resolveExpression.CompileToResolveDelegate(Constants.ResolveContextParameterExpression)); }
public ResolveContext(DependencyInjectionContainer container, DependencyOverrides dependencyOverrides) { _container = container.MustNotBeNull(nameof(container)); _dependencyOverrides = dependencyOverrides; }
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 Expression CreateResolveExpressionRecursively(TypeKey requestedTypeKey, DependencyInjectionContainer container, DependencyOverrides dependencyOverrides, bool?tryResolveAll = null) { // Check if the instance is overridden if (dependencyOverrides?.HasOverriddenInstance(requestedTypeKey) == true) { return(Expression.Convert(Expression.Call(Expression.Call(Constants.ResolveContextParameterExpression, Constants.GetDependencyOverridesProperty), Constants.GetOverriddenInstanceMethod, Expression.Constant(requestedTypeKey)), requestedTypeKey.Type)); } // Else ask the container for a ResolveInfo to identify how the returned expression should be composed var resolveInfo = container.GetResolveInfo(requestedTypeKey, tryResolveAll); if (resolveInfo is ResolveRegistrationInfo resolveRegistrationInfo) { return(CreateResolveExpressionRecursively(requestedTypeKey, resolveRegistrationInfo.Registration, dependencyOverrides, container)); } if (resolveInfo is ResolveAllInfo resolveAllInfo) { return(CreateResolveAllExpressionRecursively(resolveAllInfo, dependencyOverrides, container)); } throw new InvalidOperationException($"Cannot handle ResolveInfo \"{resolveInfo}\" in this current implementation of \"{nameof(CompiledLinqExpressionFactory)}\""); }
private Expression CreateResolveAllExpressionRecursively(ResolveAllInfo resolveAllInfo, DependencyOverrides dependencyOverrides, DependencyInjectionContainer container) { // Create the expression that instantiates the target collection var collectionRegistration = container.GetRegistration(resolveAllInfo.CollectionType); if (collectionRegistration == null) { throw new ResolveException($"There is no registration present to resolve collection type \"{resolveAllInfo.CollectionType}\"."); } var createCollectionExpression = CreateConstructionExpression(new ResolveExpressionContext(new TypeKey(resolveAllInfo.CollectionType), collectionRegistration, dependencyOverrides, container)); // Create the expression block that assigns the created collection to a variable, casts this variable to IList<TargetType>, and then resolves all registrations, adding the resulting the expressions var blockExpressions = new Expression[resolveAllInfo.Registrations.Count + 3]; // +3 for initial assignment, casting to IList<ItemType>, and return statement var variableExpression = Expression.Variable(resolveAllInfo.CollectionType); var assignVariableExpression = Expression.Assign(variableExpression, createCollectionExpression); blockExpressions[0] = assignVariableExpression; // Assign created collection to variable var closedConstructedICollectionType = Constants.ICollectionGenericTypeDefinition.MakeGenericType(resolveAllInfo.ItemType); var castedICollectionVariableExpression = Expression.Variable(closedConstructedICollectionType); var assignCastedListExpression = Expression.Assign(castedICollectionVariableExpression, Expression.ConvertChecked(variableExpression, closedConstructedICollectionType)); blockExpressions[1] = assignCastedListExpression; // Assign casted list to variable // Resolve all registrations and add them to the collection var addMethodInfo = closedConstructedICollectionType.GetRuntimeMethod("Add", new[] { resolveAllInfo.ItemType }); for (var i = 0; i < resolveAllInfo.Registrations.Count; i++) { var registration = resolveAllInfo.Registrations[i]; var itemTypeKey = new TypeKey(resolveAllInfo.ItemType, registration.RegistrationName); var resolveRegistrationExpression = CreateResolveExpressionRecursively(itemTypeKey, registration, dependencyOverrides, container); blockExpressions[i + 2] = Expression.Call(castedICollectionVariableExpression, addMethodInfo, resolveRegistrationExpression); } blockExpressions[blockExpressions.Length - 1] = variableExpression; // Return statement return(Expression.Block(resolveAllInfo.CollectionType, new[] { variableExpression, castedICollectionVariableExpression }, blockExpressions)); }
public ResolveDelegateId(TypeKey typeKey, DependencyOverrides overrides = null) { TypeKey = typeKey.MustNotBeEmpty(nameof(typeKey)); Overrides = overrides; HashCode = Overrides == null ? TypeKey.HashCode : Equality.CreateHashCode(TypeKey, overrides); }