<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0-preview.7.24405.7" />

ActivatorUtilities

public static class ActivatorUtilities
Helper code for the various activator services.
using Microsoft.Extensions.Internal; using System; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; namespace Microsoft.Extensions.DependencyInjection { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public static class ActivatorUtilities { private readonly struct FactoryParameterContext { public Type ParameterType { get; } public bool HasDefaultValue { get; } public object DefaultValue { get; } public int ArgumentIndex { get; } public object ServiceKey { get; } public FactoryParameterContext(Type parameterType, bool hasDefaultValue, object defaultValue, int argumentIndex, object serviceKey) { ParameterType = parameterType; HasDefaultValue = hasDefaultValue; DefaultValue = defaultValue; ArgumentIndex = argumentIndex; ServiceKey = serviceKey; } } private sealed class ConstructorInfoEx { public readonly ConstructorInfo Info; public readonly ParameterInfo[] Parameters; public readonly bool IsPreferred; private readonly object[] _parameterKeys; public ConstructorInfoEx(ConstructorInfo constructor) { Info = constructor; Parameters = constructor.GetParameters(); IsPreferred = constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), false); for (int i = 0; i < Parameters.Length; i++) { FromKeyedServicesAttribute fromKeyedServicesAttribute = (FromKeyedServicesAttribute)Attribute.GetCustomAttribute(Parameters[i], typeof(FromKeyedServicesAttribute), false); if (fromKeyedServicesAttribute != null) { if (_parameterKeys == null) _parameterKeys = new object[Parameters.Length]; _parameterKeys[i] = fromKeyedServicesAttribute.Key; } } } public bool IsService(IServiceProviderIsService serviceProviderIsService, int parameterIndex) { ParameterInfo parameterInfo = Parameters[parameterIndex]; object[] parameterKeys = _parameterKeys; object obj = (parameterKeys != null) ? parameterKeys[parameterIndex] : null; if (obj != null) { IServiceProviderIsKeyedService serviceProviderIsKeyedService = serviceProviderIsService as IServiceProviderIsKeyedService; if (serviceProviderIsKeyedService != null) return serviceProviderIsKeyedService.IsKeyedService(parameterInfo.ParameterType, obj); throw new InvalidOperationException(System.SR.KeyedServicesNotSupported); } return serviceProviderIsService.IsService(parameterInfo.ParameterType); } public object GetService(IServiceProvider serviceProvider, int parameterIndex) { ParameterInfo parameterInfo = Parameters[parameterIndex]; object[] parameterKeys = _parameterKeys; object obj = (parameterKeys != null) ? parameterKeys[parameterIndex] : null; if (obj != null) { IKeyedServiceProvider keyedServiceProvider = serviceProvider as IKeyedServiceProvider; if (keyedServiceProvider != null) return keyedServiceProvider.GetKeyedService(parameterInfo.ParameterType, obj); throw new InvalidOperationException(System.SR.KeyedServicesNotSupported); } return serviceProvider.GetService(parameterInfo.ParameterType); } } private readonly ref struct ConstructorMatcher { private readonly ConstructorInfoEx _constructor; private readonly object[] _parameterValues; public ConstructorInfoEx ConstructorInfo => _constructor; public ConstructorMatcher(ConstructorInfoEx constructor, object[] parameterValues) { _constructor = constructor; _parameterValues = parameterValues; } public int Match(object[] givenParameters, IServiceProviderIsService serviceProviderIsService) { for (int i = 0; i < givenParameters.Length; i++) { Type c = givenParameters[i]?.GetType(); bool flag = false; for (int j = 0; j < _constructor.Parameters.Length; j++) { if (_parameterValues[j] == null && _constructor.Parameters[j].ParameterType.IsAssignableFrom(c)) { flag = true; _parameterValues[j] = givenParameters[i]; break; } } if (!flag) return -1; } for (int k = 0; k < _constructor.Parameters.Length; k++) { if (_parameterValues[k] == null && !_constructor.IsService(serviceProviderIsService, k)) { if (!ParameterDefaultValue.TryGetDefaultValue(_constructor.Parameters[k], out object defaultValue)) return -1; _parameterValues[k] = defaultValue; } } return _constructor.Parameters.Length; } public object CreateInstance(IServiceProvider provider) { for (int i = 0; i < _constructor.Parameters.Length; i++) { if (_parameterValues[i] == null) { object service = _constructor.GetService(provider, i); if (service == null) { if (!ParameterDefaultValue.TryGetDefaultValue(_constructor.Parameters[i], out object defaultValue)) throw new InvalidOperationException(System.SR.Format(System.SR.UnableToResolveService, _constructor.Parameters[i].ParameterType, _constructor.Info.DeclaringType)); _parameterValues[i] = defaultValue; } else _parameterValues[i] = service; } } try { return _constructor.Info.Invoke(_parameterValues); } catch (TargetInvocationException ex) when (ex.InnerException != null) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); throw; } } public void MapParameters(int?[] parameterMap, object[] givenParameters) { for (int i = 0; i < _constructor.Parameters.Length; i++) { if (parameterMap[i].HasValue) _parameterValues[i] = givenParameters[parameterMap[i].Value]; } } } private static readonly MethodInfo GetServiceInfo = new Func<IServiceProvider, Type, Type, bool, object, object>(GetService).Method; public static object CreateInstance(IServiceProvider provider, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, params object[] parameters) { if (provider == null) throw new ArgumentNullException("provider"); if (instanceType.IsAbstract) throw new InvalidOperationException(System.SR.CannotCreateAbstractClasses); ConstructorInfoEx[] array = CreateConstructorInfoExs(instanceType); object[] ctorArgs = null; object[] array2 = null; ConstructorMatcher constructorMatcher = default(ConstructorMatcher); IServiceProviderIsService service = provider.GetService<IServiceProviderIsService>(); ConstructorInfoEx constructorInfoEx; if (service != null) { for (int i = 0; i < array.Length; i++) { constructorInfoEx = array[i]; if (constructorInfoEx.IsPreferred) { for (int j = i + 1; j < array.Length; j++) { if (array[j].IsPreferred) ThrowMultipleCtorsMarkedWithAttributeException(); } <CreateInstance>g__InitializeCtorArgValues|1_0(ref ctorArgs, constructorInfoEx.Parameters.Length); constructorMatcher = new ConstructorMatcher(constructorInfoEx, ctorArgs); if (constructorMatcher.Match(parameters, service) == -1) ThrowMarkedCtorDoesNotTakeAllProvidedArguments(); return constructorMatcher.CreateInstance(provider); } } int num = -1; ConstructorMatcher constructorMatcher2 = default(ConstructorMatcher); bool flag = false; for (int k = 0; k < array.Length; k++) { constructorInfoEx = array[k]; <CreateInstance>g__InitializeCtorArgValues|1_0(ref ctorArgs, constructorInfoEx.Parameters.Length); constructorMatcher = new ConstructorMatcher(constructorInfoEx, ctorArgs); int num2 = constructorMatcher.Match(parameters, service); if (num < num2) { num = num2; if (k == array.Length - 1) array2 = ctorArgs; else { array2 = new object[num2]; ctorArgs.CopyTo(array2, 0); } constructorMatcher2 = new ConstructorMatcher(constructorMatcher.ConstructorInfo, array2); flag = false; } else if (num == num2) { flag = true; } } if (num != -1) { if (flag) throw new InvalidOperationException(System.SR.Format(System.SR.MultipleCtorsFoundWithBestLength, instanceType, num)); return constructorMatcher2.CreateInstance(provider); } } Type[] array3; if (parameters.Length == 0) array3 = Type.EmptyTypes; else { array3 = new Type[parameters.Length]; for (int l = 0; l < array3.Length; l++) { array3[l] = parameters[l]?.GetType(); } } FindApplicableConstructor(instanceType, array3, array, out ConstructorInfo matchingConstructor, out int?[] matchingParameterMap); constructorInfoEx = FindConstructorEx(matchingConstructor, array); <CreateInstance>g__InitializeCtorArgValues|1_0(ref ctorArgs, constructorInfoEx.Parameters.Length); constructorMatcher = new ConstructorMatcher(constructorInfoEx, ctorArgs); constructorMatcher.MapParameters(matchingParameterMap, parameters); return constructorMatcher.CreateInstance(provider); } private static ConstructorInfoEx[] CreateConstructorInfoExs([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) { ConstructorInfo[] constructors = type.GetConstructors(); ConstructorInfoEx[] array = new ConstructorInfoEx[constructors.Length]; for (int i = 0; i < constructors.Length; i++) { array[i] = new ConstructorInfoEx(constructors[i]); } return array; } public static ObjectFactory CreateFactory([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes) { CreateFactoryInternal(instanceType, argumentTypes, out ParameterExpression provider, out ParameterExpression argumentArray, out Expression factoryExpressionBody); return Expression.Lambda<Func<IServiceProvider, object[], object>>(factoryExpressionBody, new ParameterExpression[2] { provider, argumentArray }).Compile().Invoke; } public static ObjectFactory<T> CreateFactory<[System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Type[] argumentTypes) { CreateFactoryInternal(typeof(T), argumentTypes, out ParameterExpression provider, out ParameterExpression argumentArray, out Expression factoryExpressionBody); return Expression.Lambda<Func<IServiceProvider, object[], T>>(factoryExpressionBody, new ParameterExpression[2] { provider, argumentArray }).Compile().Invoke; } private static void CreateFactoryInternal([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes, out ParameterExpression provider, out ParameterExpression argumentArray, out Expression factoryExpressionBody) { FindApplicableConstructor(instanceType, argumentTypes, null, out ConstructorInfo matchingConstructor, out int?[] matchingParameterMap); provider = Expression.Parameter(typeof(IServiceProvider), "provider"); argumentArray = Expression.Parameter(typeof(object[]), "argumentArray"); factoryExpressionBody = BuildFactoryExpression(matchingConstructor, matchingParameterMap, provider, argumentArray); } public static T CreateInstance<[System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] T>(IServiceProvider provider, params object[] parameters) { return (T)CreateInstance(provider, typeof(T), parameters); } public static T GetServiceOrCreateInstance<[System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] T>(IServiceProvider provider) { return (T)GetServiceOrCreateInstance(provider, typeof(T)); } public static object GetServiceOrCreateInstance(IServiceProvider provider, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) { return provider.GetService(type) ?? CreateInstance(provider, type, Array.Empty<object>()); } private static object GetService(IServiceProvider sp, Type type, Type requiredBy, bool hasDefaultValue, object key) { object obj = (key == null) ? sp.GetService(type) : GetKeyedService(sp, type, key); if (obj == null && !hasDefaultValue) ThrowHelperUnableToResolveService(type, requiredBy); return obj; } [System.Diagnostics.CodeAnalysis.DoesNotReturn] private static void ThrowHelperUnableToResolveService(Type type, Type requiredBy) { throw new InvalidOperationException(System.SR.Format(System.SR.UnableToResolveService, type, requiredBy)); } private static BlockExpression BuildFactoryExpression(ConstructorInfo constructor, int?[] parameterMap, Expression serviceProvider, Expression factoryArgumentArray) { ParameterInfo[] parameters = constructor.GetParameters(); Expression[] array = new Expression[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { ParameterInfo parameterInfo = parameters[i]; Type parameterType = parameterInfo.ParameterType; object defaultValue; bool flag = ParameterDefaultValue.TryGetDefaultValue(parameterInfo, out defaultValue); if (parameterMap[i].HasValue) array[i] = Expression.ArrayAccess(factoryArgumentArray, Expression.Constant(parameterMap[i])); else { FromKeyedServicesAttribute fromKeyedServicesAttribute = (FromKeyedServicesAttribute)Attribute.GetCustomAttribute(parameterInfo, typeof(FromKeyedServicesAttribute), false); Expression[] arguments = new Expression[5] { serviceProvider, Expression.Constant(parameterType, typeof(Type)), Expression.Constant(constructor.DeclaringType, typeof(Type)), Expression.Constant(flag), Expression.Constant(fromKeyedServicesAttribute?.Key) }; array[i] = Expression.Call(GetServiceInfo, arguments); } if (flag) { ConstantExpression right = Expression.Constant(defaultValue); array[i] = Expression.Coalesce(array[i], right); } array[i] = Expression.Convert(array[i], parameterType); } return Expression.Block(Expression.IfThen(Expression.Equal(serviceProvider, Expression.Constant(null)), Expression.Throw(Expression.Constant(new ArgumentNullException("serviceProvider")))), Expression.New(constructor, array)); } private static void FindApplicableConstructor([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes, ConstructorInfoEx[] constructors, out ConstructorInfo matchingConstructor, out int?[] matchingParameterMap) { if (!TryFindPreferredConstructor(instanceType, argumentTypes, constructors, out ConstructorInfo matchingConstructor2, out int?[] parameterMap) && !TryFindMatchingConstructor(instanceType, argumentTypes, out matchingConstructor2, out parameterMap)) throw new InvalidOperationException(System.SR.Format(System.SR.CtorNotLocated, instanceType)); matchingConstructor = matchingConstructor2; matchingParameterMap = parameterMap; } private static ConstructorInfoEx FindConstructorEx(ConstructorInfo constructorInfo, ConstructorInfoEx[] constructorExs) { for (int i = 0; i < constructorExs.Length; i++) { if ((object)constructorExs[i].Info == constructorInfo) return constructorExs[i]; } return null; } private static bool TryFindMatchingConstructor([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ConstructorInfo matchingConstructor, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out int?[] parameterMap) { matchingConstructor = null; parameterMap = null; ConstructorInfo[] constructors = instanceType.GetConstructors(); foreach (ConstructorInfo constructorInfo in constructors) { if (TryCreateParameterMap(constructorInfo.GetParameters(), argumentTypes, out int?[] parameterMap2)) { if (matchingConstructor != (ConstructorInfo)null) throw new InvalidOperationException(System.SR.Format(System.SR.MultipleCtorsFound, instanceType)); matchingConstructor = constructorInfo; parameterMap = parameterMap2; } } if (matchingConstructor != (ConstructorInfo)null) return true; return false; } private static bool TryFindPreferredConstructor([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes, ConstructorInfoEx[] constructors, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ConstructorInfo matchingConstructor, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out int?[] parameterMap) { bool flag = false; matchingConstructor = null; parameterMap = null; if (constructors == null) constructors = CreateConstructorInfoExs(instanceType); ConstructorInfoEx[] array = constructors; foreach (ConstructorInfoEx constructorInfoEx in array) { if (constructorInfoEx.IsPreferred) { if (flag) ThrowMultipleCtorsMarkedWithAttributeException(); if (!TryCreateParameterMap(constructorInfoEx.Info.GetParameters(), argumentTypes, out int?[] parameterMap2)) ThrowMarkedCtorDoesNotTakeAllProvidedArguments(); matchingConstructor = constructorInfoEx.Info; parameterMap = parameterMap2; flag = true; } } if (matchingConstructor != (ConstructorInfo)null) return true; return false; } private static bool TryCreateParameterMap(ParameterInfo[] constructorParameters, Type[] argumentTypes, out int?[] parameterMap) { parameterMap = new int?[constructorParameters.Length]; for (int i = 0; i < argumentTypes.Length; i++) { bool flag = false; Type c = argumentTypes[i]; for (int j = 0; j < constructorParameters.Length; j++) { if (!parameterMap[j].HasValue && constructorParameters[j].ParameterType.IsAssignableFrom(c)) { flag = true; parameterMap[j] = i; break; } } if (!flag) return false; } return true; } private static void ThrowMultipleCtorsMarkedWithAttributeException() { throw new InvalidOperationException(System.SR.Format(System.SR.MultipleCtorsMarkedWithAttribute, "ActivatorUtilitiesConstructorAttribute")); } private static void ThrowMarkedCtorDoesNotTakeAllProvidedArguments() { throw new InvalidOperationException(System.SR.Format(System.SR.MarkedCtorMissingArgumentTypes, "ActivatorUtilitiesConstructorAttribute")); } private static object GetKeyedService(IServiceProvider provider, Type type, object serviceKey) { System.ThrowHelper.ThrowIfNull(provider, "provider"); IKeyedServiceProvider keyedServiceProvider = provider as IKeyedServiceProvider; if (keyedServiceProvider != null) return keyedServiceProvider.GetKeyedService(type, serviceKey); throw new InvalidOperationException(System.SR.KeyedServicesNotSupported); } } }