Stashbox by Peter Csajtai

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

 ExpressionBuilder

static class ExpressionBuilder
using Stashbox.Exceptions; using Stashbox.Lifetime; using Stashbox.Registration; using Stashbox.Resolution; using Stashbox.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; namespace Stashbox.Expressions { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] internal static class ExpressionBuilder { [return: System.Runtime.CompilerServices.Nullable(2)] internal static Expression BuildExpressionForRegistration(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType) { Expression expression = BuildExpressionByRegistrationType(serviceRegistration, resolutionContext, requestedType); if (expression == null) return null; if (serviceRegistration.Options != null && !serviceRegistration.IsInstance()) { if (serviceRegistration.Options.TryGetValue(RegistrationOption.AsyncInitializer, out object value)) expression = resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddWithAsyncInitializerMethod, expression, value.AsConstant()).ConvertTo(requestedType); if (serviceRegistration.Options.TryGetValue(RegistrationOption.Finalizer, out object value2)) expression = resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddWithFinalizerMethod, expression, value2.AsConstant()).ConvertTo(requestedType); } if (!ShouldHandleDisposal(resolutionContext.CurrentContainerContext, serviceRegistration) || !expression.Type.IsDisposable()) return expression; if (!resolutionContext.RequestConfiguration.RequiresRequestContext) return resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddDisposalMethod, expression).ConvertTo(requestedType); return resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddRequestContextAwareDisposalMethod, expression, resolutionContext.RequestContextParameter).ConvertTo(requestedType); } [return: System.Runtime.CompilerServices.Nullable(2)] private static Expression BuildExpressionByRegistrationType(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type requestedType) { resolutionContext = (resolutionContext.ShouldFallBackToRequestInitiatorContext ? resolutionContext.BeginCrossContainerContext(resolutionContext.RequestInitiatorContainerContext) : resolutionContext); Dictionary<RegistrationOption, object> options = serviceRegistration.Options; object obj = (options != null) ? options.GetOrDefault(RegistrationOption.RegistrationTypeOptions) : null; FactoryOptions factoryOptions = obj as FactoryOptions; if (factoryOptions != null) return GetExpressionForFactory(serviceRegistration, factoryOptions, resolutionContext, requestedType); InstanceOptions instanceOptions = obj as InstanceOptions; if (instanceOptions != null) return instanceOptions.IsWireUp ? ExpressionFactory.ConstructBuildUpExpression(serviceRegistration, resolutionContext, instanceOptions.ExistingInstance.AsConstant(), serviceRegistration.ImplementationType) : instanceOptions.ExistingInstance.AsConstant(); Delegate delegate = obj as Delegate; if ((object)delegate != null) return GetExpressionForFunc(serviceRegistration, delegate, resolutionContext); return GetExpressionForDefault(serviceRegistration, resolutionContext); } private static bool ShouldHandleDisposal(IContainerContext containerContext, ServiceRegistration serviceRegistration) { if (serviceRegistration.Options.IsOn(RegistrationOption.IsLifetimeExternallyOwned) || serviceRegistration.IsInstance()) return false; if (!containerContext.ContainerConfiguration.TrackTransientsForDisposalEnabled) return !(serviceRegistration.Lifetime is TransientLifetime); return true; } [return: System.Runtime.CompilerServices.Nullable(2)] private static Expression GetExpressionForDefault(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext) { if (resolutionContext.CircularDependencyBarrier.Contains(serviceRegistration.RegistrationId)) throw new CircularDependencyException(serviceRegistration.ImplementationType, null); resolutionContext.CircularDependencyBarrier.Add(serviceRegistration.RegistrationId); Expression result = PrepareDefaultExpression(serviceRegistration, resolutionContext); resolutionContext.CircularDependencyBarrier.Pop(); return result; } [return: System.Runtime.CompilerServices.Nullable(2)] private static Expression PrepareDefaultExpression(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext) { object orDefault = serviceRegistration.Options.GetOrDefault(RegistrationOption.DefinedScopeName); if (orDefault != null) { ParameterExpression parameterExpression = Constants.ResolutionScopeType.AsVariable(null); MethodCallExpression expression = resolutionContext.CurrentScopeParameter.CallMethod(Constants.BeginScopeMethod, orDefault.AsConstant(), true.AsConstant()); ResolutionContext resolutionContext2 = resolutionContext.BeginNewScopeContext(new ReadOnlyKeyValue<object, ParameterExpression>(orDefault, parameterExpression)); resolutionContext.AddDefinedVariable(parameterExpression); resolutionContext.AddInstruction(parameterExpression.AssignTo(expression.ConvertTo(Constants.ResolutionScopeType))); Expression result = ExpressionFactory.ConstructExpression(serviceRegistration, resolutionContext2); foreach (ParameterExpression item in resolutionContext2.DefinedVariables.Walk()) { resolutionContext.AddDefinedVariable(item); } { foreach (Expression singleInstruction in resolutionContext2.SingleInstructions) { resolutionContext.AddInstruction(singleInstruction); } return result; } } return ExpressionFactory.ConstructExpression(serviceRegistration, resolutionContext); } private static Expression GetExpressionForFactory(ServiceRegistration serviceRegistration, FactoryOptions factoryOptions, ResolutionContext resolutionContext, Type resolveType) { if (resolutionContext.CircularDependencyBarrier.Contains(serviceRegistration.RegistrationId)) throw new CircularDependencyException(serviceRegistration.ImplementationType, null); resolutionContext.CircularDependencyBarrier.Add(serviceRegistration.RegistrationId); IEnumerable<Expression> factoryParameters = GetFactoryParameters(factoryOptions, resolutionContext); Expression instance = ConstructFactoryExpression(factoryOptions, factoryParameters); Expression result = ExpressionFactory.ConstructBuildUpExpression(serviceRegistration, resolutionContext, instance, resolveType); resolutionContext.CircularDependencyBarrier.Pop(); return result; } private static Expression ConstructFactoryExpression(FactoryOptions factoryOptions, IEnumerable<Expression> parameters) { if (factoryOptions.IsFactoryDelegateACompiledLambda || factoryOptions.Factory.IsCompiledLambda()) return factoryOptions.Factory.InvokeDelegate(parameters); MethodInfo method = factoryOptions.Factory.GetMethod(); if (!method.IsStatic) return method.CallMethod(factoryOptions.Factory.Target.AsConstant(), parameters); return method.CallStaticMethod(parameters); } private static IEnumerable<Expression> GetFactoryParameters(FactoryOptions factoryOptions, ResolutionContext resolutionContext) { int length = factoryOptions.FactoryParameters.Length; for (int i = 0; i < length - 1; i++) { TypeInformation typeInformation = new TypeInformation(factoryOptions.FactoryParameters[i], null); yield return resolutionContext.CurrentContainerContext.ResolutionStrategy.BuildExpressionForType(resolutionContext, typeInformation).ServiceExpression; } } private static Expression GetExpressionForFunc(ServiceRegistration serviceRegistration, Delegate func, ResolutionContext resolutionContext) { MethodInfo method = func.GetMethod(); Expression[] funcParametersWithScope = GetFuncParametersWithScope(serviceRegistration.ImplementationType.GetMethod("Invoke").GetParameters(), resolutionContext); if (func.IsCompiledLambda()) return func.InvokeDelegate(funcParametersWithScope).AsLambda(funcParametersWithScope.Take(funcParametersWithScope.Length - 1).Cast<ParameterExpression>()); return (method.IsStatic ? method.CallStaticMethod(funcParametersWithScope) : func.Target.AsConstant().CallMethod(method, funcParametersWithScope)).AsLambda(funcParametersWithScope.Take(funcParametersWithScope.Length - 1).Cast<ParameterExpression>()); } private static Expression[] GetFuncParametersWithScope(IList<ParameterInfo> parameterInfos, ResolutionContext resolutionContext) { int count = parameterInfos.Count; Expression[] array = new Expression[count + 1]; for (int i = 0; i < count; i++) { array[i] = parameterInfos[i].ParameterType.AsParameter(null); } Expression[] array2 = array; array2[array2.Length - 1] = resolutionContext.CurrentScopeParameter; return array; } } }