/// <summary> /// get activation strategy delegate /// </summary> /// <param name="scope"></param> /// <param name="request"></param> /// <returns></returns> public override IActivationExpressionResult GetActivationExpression(IInjectionScope scope, IActivationExpressionRequest request) { var closedClass = typeof(TypedDelegateExpression <>).MakeGenericType(request.ActivationType.GenericTypeArguments); var closedMethod = closedClass.GetRuntimeMethod(nameof(TypedDelegateExpression <object> .CreateFunc), new Type[] { }); var instance = Activator.CreateInstance(closedClass, scope, request, this); request.RequireExportScope(); request.RequireDisposalScope(); var callExpression = Expression.Call(Expression.Constant(instance), closedMethod); return(request.Services.Compiler.CreateNewResult(request, callExpression)); }
/// <summary> /// Get an activation expression for this strategy /// </summary> /// <param name="scope"></param> /// <param name="request"></param> /// <returns></returns> public override IActivationExpressionResult GetActivationExpression(IInjectionScope scope, IActivationExpressionRequest request) { var closedClass = typeof(FuncExpression <, , ,>).MakeGenericType(request.ActivationType.GenericTypeArguments); var closedMethod = closedClass.GetRuntimeMethod(nameof(FuncExpression <object, object, object, object> .CreateFunc), new[] { typeof(IExportLocatorScope), typeof(IDisposalScope), typeof(IInjectionContext) }); var instance = Activator.CreateInstance(closedClass, scope, request, request.Services.InjectionContextCreator, this); request.RequireExportScope(); request.RequireDisposalScope(); var callExpression = Expression.Call(Expression.Constant(instance), closedMethod, request.ScopeParameter, request.DisposalScopeExpression, request.InjectionContextParameter); return(request.Services.Compiler.CreateNewResult(request, callExpression)); }
/// <summary> /// Create expression to add instance to disposal scope /// </summary> /// <param name="scope">scope for strategy</param> /// <param name="request">request</param> /// <param name="activationConfiguration">activation configuration</param> /// <param name="result">result for instantiation</param> /// <returns></returns> public IActivationExpressionResult CreateExpression(IInjectionScope scope, IActivationExpressionRequest request, TypeActivationConfiguration activationConfiguration, IActivationExpressionResult result) { var closedActionType = typeof(Action <>).MakeGenericType(activationConfiguration.ActivationType); object disposalDelegate = null; if (closedActionType == activationConfiguration.DisposalDelegate?.GetType()) { disposalDelegate = activationConfiguration.DisposalDelegate; } MethodInfo closedGeneric; Expression[] parameterExpressions; var resultExpression = result.Expression; if (resultExpression.Type != activationConfiguration.ActivationType) { resultExpression = Expression.Convert(resultExpression, activationConfiguration.ActivationType); } if (disposalDelegate != null) { closedGeneric = AddMethodWithCleanup.MakeGenericMethod(activationConfiguration.ActivationType); parameterExpressions = new[] { resultExpression, Expression.Convert(Expression.Constant(disposalDelegate), closedActionType) }; } else { closedGeneric = AddMethod.MakeGenericMethod(activationConfiguration.ActivationType); parameterExpressions = new[] { resultExpression }; } request.RequireDisposalScope(); var disposalCall = Expression.Call(request.DisposalScopeExpression, closedGeneric, parameterExpressions); var disposalResult = request.Services.Compiler.CreateNewResult(request, disposalCall); disposalResult.AddExpressionResult(result); return(disposalResult); }
/// <summary> /// Get an activation expression for this strategy /// </summary> /// <param name="scope"></param> /// <param name="request"></param> /// <returns></returns> public override IActivationExpressionResult GetActivationExpression(IInjectionScope scope, IActivationExpressionRequest request) { var invokeMethod = request.ActivationType.GetTypeInfo().GetDeclaredMethod("Invoke"); var list = new List <Type>(invokeMethod.GetParameters().Select(p => p.ParameterType)); list.Add(invokeMethod.ReturnType); list.Add(request.ActivationType); var closedClass = typeof(DelegateExpression <, ,>).MakeGenericType(list.ToArray()); var closedMethod = closedClass.GetRuntimeMethod(nameof(DelegateExpression <object, object, object> .CreateDelegate), new[] { typeof(IExportLocatorScope), typeof(IDisposalScope), typeof(IInjectionContext) }); var instance = Activator.CreateInstance(closedClass, scope, request, request.Services.InjectionContextCreator, this); request.RequireExportScope(); request.RequireDisposalScope(); var callExpression = Expression.Call(Expression.Constant(instance), closedMethod, request.ScopeParameter, request.DisposalScopeExpression, request.InjectionContextParameter); return(request.Services.Compiler.CreateNewResult(request, callExpression)); }
/// <inheritdoc /> protected override IActivationExpressionResult CreateExpression(IInjectionScope scope, IActivationExpressionRequest request, ICompiledLifestyle lifestyle) { if (_proxyType == null) { lock (_proxyTypeLock) { if (_proxyType == null) { var builder = new DynamicTypeBuilder(); _proxyType = builder.CreateType(ActivationType, out _delegateInfo); } } } request.RequireExportScope(); request.RequireDisposalScope(); request.RequireInjectionContext(); var parameters = new List <Expression> { request.ScopeParameter, request.DisposalScopeExpression, request.InjectionContextParameter }; var uniqueId = UniqueStringId.Generate(); foreach (var delegateInfo in _delegateInfo) { var locateType = delegateInfo.Method.ReturnType; var newRequest = request.NewRequest(locateType, this, ActivationType, RequestType.Other, null, true); newRequest.AddKnownValueExpression( CreateKnownValueExpression(newRequest, ActivationType, uniqueId)); if (delegateInfo.Method.Name.StartsWith("Get")) { newRequest.SetLocateKey(delegateInfo.Method.Name.Substring("Get".Length)); } if (delegateInfo.ParameterInfos != null) { foreach (var parameter in delegateInfo.ParameterInfos) { newRequest.AddKnownValueExpression( CreateKnownValueExpression(newRequest, parameter.ParameterInfo.ParameterType, parameter.UniqueId, parameter.ParameterInfo.Name, parameter.ParameterInfo.Position)); } } var result = request.Services.ExpressionBuilder.GetActivationExpression(request.RequestingScope, newRequest); var compiledDelegate = request.Services.Compiler.CompileDelegate(request.RequestingScope, result); parameters.Add(Expression.Constant(compiledDelegate)); } var constructor = _proxyType.GetTypeInfo().DeclaredConstructors.First(); request.RequireInjectionContext(); var newStatement = Expression.New(constructor, parameters); var setMethod = typeof(IExtraDataContainer).GetRuntimeMethod(nameof(IExtraDataContainer.SetExtraData), new[] { typeof(object), typeof(object), typeof(bool) }); var invokeStatement = Expression.Call(request.InjectionContextParameter, setMethod, Expression.Constant(uniqueId), newStatement, Expression.Constant(true)); var castStatement = Expression.Convert(invokeStatement, ActivationType); return(request.Services.Compiler.CreateNewResult(request, castStatement)); }
/// <summary> /// Applies null check and disposal scope tracking logic to an expression /// </summary> /// <param name="scope"></param> /// <param name="request"></param> /// <param name="expression"></param> /// <param name="allowDisposableTracking"></param> /// <param name="allowNull"></param> /// <returns></returns> public static Expression ApplyNullCheckAndAddDisposal(IInjectionScope scope, IActivationExpressionRequest request, Expression expression, bool allowDisposableTracking, bool allowNull) { if (expression.Type != request.ActivationType && !ReflectionService.CheckTypeIsBasedOnAnotherType(expression.Type, request.ActivationType)) { expression = Expression.Convert(expression, request.ActivationType); } if (!allowDisposableTracking) { if (request.DefaultValue != null) { var method = typeof(ExpressionUtilities).GetRuntimeMethods() .FirstOrDefault(m => m.Name == nameof(ValueOrDefault)); var closedMethod = method.MakeGenericMethod(request.ActivationType); return(Expression.Call(closedMethod, expression, Expression.Constant(request.DefaultValue.DefaultValue, request.ActivationType))); } if (!allowNull && !scope.ScopeConfiguration.Behaviors.AllowInstanceAndFactoryToReturnNull && request.IsRequired) { var closedMethod = CheckForNullMethodInfo.MakeGenericMethod(request.ActivationType); return(Expression.Call(closedMethod, Expression.Constant(request.GetStaticInjectionContext()), expression)); } return(expression); } if (request.DefaultValue != null) { request.RequireDisposalScope(); var method = typeof(ExpressionUtilities).GetRuntimeMethods() .FirstOrDefault(m => m.Name == nameof(AddToDisposableScopeOrDefault)); var closedMethod = method.MakeGenericMethod(request.ActivationType); return(Expression.Call(closedMethod, request.DisposalScopeExpression, expression, Expression.Constant(request.DefaultValue.DefaultValue, request.ActivationType))); } if (allowNull || scope.ScopeConfiguration.Behaviors.AllowInstanceAndFactoryToReturnNull || !request.IsRequired) { request.RequireDisposalScope(); var closedMethod = AddToDisposalScopeMethodInfo.MakeGenericMethod(request.ActivationType); return(Expression.Call(closedMethod, request.DisposalScopeExpression, expression)); } else { request.RequireDisposalScope(); var closedMethod = CheckForNullAndAddToDisposalScopeMethodInfo.MakeGenericMethod(request.ActivationType); return(Expression.Call(closedMethod, request.DisposalScopeExpression, Expression.Constant(request.GetStaticInjectionContext()), expression)); } }
/// <summary> /// Get expression result from request /// </summary> /// <param name="scope"></param> /// <param name="request"></param> /// <param name="activationType"></param> /// <param name="key"></param> /// <returns></returns> protected virtual IActivationExpressionResult GetValueFromRequest(IInjectionScope scope, IActivationExpressionRequest request, Type activationType, object key) { var knownValues = request.KnownValueExpressions.Where( v => activationType.GetTypeInfo().IsAssignableFrom(v.ActivationType.GetTypeInfo())).ToArray(); if (knownValues.Length > 0) { if (knownValues.Length == 1) { return(knownValues[0].ValueExpression(request)); } if (key != null) { IKnownValueExpression knownValue; if (key is string keyString) { knownValue = knownValues.FirstOrDefault(v => string.Compare(keyString, v.Key as string, StringComparison.CurrentCultureIgnoreCase) == 0); } else { knownValue = knownValues.FirstOrDefault(v => v.Key == key); } if (knownValue != null) { return(knownValue.ValueExpression(request)); } } if (request.Info is MemberInfo memberInfo) { var knownValue = knownValues.FirstOrDefault(v => Equals(v.Key, memberInfo.Name)); if (knownValue != null) { return(knownValue.ValueExpression(request)); } } if (request.Info is ParameterInfo parameterInfo) { var knownValue = knownValues.FirstOrDefault(v => Equals(v.Key, parameterInfo.Name)); if (knownValue != null) { return(knownValue.ValueExpression(request)); } knownValue = knownValues.FirstOrDefault(v => Equals(v.Position.GetValueOrDefault(-1), parameterInfo.Position)); if (knownValue != null) { return(knownValue.ValueExpression(request)); } } return(knownValues[0].ValueExpression(request)); } if (request.WrapperPathNode != null) { var configuration = request.WrapperPathNode.Strategy.GetActivationConfiguration(activationType); if (configuration.ActivationType != null && (activationType.GetTypeInfo().IsAssignableFrom(configuration.ActivationType.GetTypeInfo()) || activationType.IsConstructedGenericType && activationType.GetGenericTypeDefinition() == configuration.ActivationType)) { var wrapper = request.PopWrapperPathNode(); return(ProcessPathNode(scope, request, activationType, wrapper)); } } else if (request.DecoratorPathNode != null) { var configuration = request.DecoratorPathNode.Strategy.GetActivationConfiguration(activationType); if (configuration.ActivationType != null && (activationType.GetTypeInfo().IsAssignableFrom(configuration.ActivationType.GetTypeInfo()) || activationType.IsConstructedGenericType && activationType.GetGenericTypeDefinition() == configuration.ActivationType)) { var decorator = request.PopDecoratorPathNode(); return(ProcessPathNode(scope, request, activationType, decorator)); } } if (request.ActivationType == typeof(IInjectionScope)) { if (!scope.ScopeConfiguration.Behaviors.AllowInjectionScopeLocation) { throw new ImportInjectionScopeException(request.GetStaticInjectionContext()); } request.RequireExportScope(); var method = typeof(IExportLocatorScopeExtensions).GetRuntimeMethod(nameof(IExportLocatorScopeExtensions.GetInjectionScope), new[] { typeof(IExportLocatorScope) }); var expression = Expression.Call(method, request.ScopeParameter); return(request.Services.Compiler.CreateNewResult(request, expression)); } if (request.ActivationType == typeof(IExportLocatorScope) || request.ActivationType == typeof(ILocatorService)) { request.RequireExportScope(); return(request.Services.Compiler.CreateNewResult(request, request.ScopeParameter)); } if (request.ActivationType == typeof(IDisposalScope) || (request.ActivationType == typeof(IDisposable) && request.RequestingScope.ScopeConfiguration.InjectIDisposable)) { request.RequireDisposalScope(); return(request.Services.Compiler.CreateNewResult(request, request.DisposalScopeExpression)); } if (request.ActivationType == typeof(IInjectionContext)) { request.RequireInjectionContext(); return(request.Services.Compiler.CreateNewResult(request, request.InjectionContextParameter)); } if (request.ActivationType == typeof(StaticInjectionContext)) { var staticContext = request.Parent != null? request.Parent.GetStaticInjectionContext() : request.GetStaticInjectionContext(); return(request.Services.Compiler.CreateNewResult(request, Expression.Constant(staticContext))); } if (request.IsDynamic) { var dynamicMethod = typeof(ActivationExpressionBuilder).GetRuntimeMethod(nameof(GetDynamicValue), new[] { typeof(IExportLocatorScope), typeof(IDisposalScope), typeof(StaticInjectionContext), typeof(IInjectionContext), typeof(object), typeof(bool), typeof(bool), typeof(object) }); var closedMethod = dynamicMethod.MakeGenericMethod(request.ActivationType); Expression defaultExpression = Expression.Constant(request.DefaultValue?.DefaultValue, typeof(object)); request.RequireExportScope(); request.RequireDisposalScope(); request.RequireInjectionContext(); var expression = Expression.Call(closedMethod, request.ScopeParameter, request.DisposalScopeExpression, Expression.Constant(request.GetStaticInjectionContext()), request.InjectionContextParameter, Expression.Constant(request.LocateKey, typeof(object)), Expression.Constant(request.IsRequired), Expression.Constant(request.DefaultValue != null), defaultExpression); return(request.Services.Compiler.CreateNewResult(request, expression)); } return(null); }