/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Shared/ActivatorUtilities/ActivatorUtilities.cs
184 строки
7 KB
Pranav K
Restore use of ParameterDefaultValue in ActivatorUtilities (#40529)
04 мар 2022, 07:56
Не верифицирован
04 мар 2022, 07:56
122a25a
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable enable using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.ExceptionServices; namespace Microsoft.Extensions.Internal; internal static class ActivatorUtilities { private const DynamicallyAccessedMemberTypes ActivatorAccessibility = DynamicallyAccessedMemberTypes.PublicConstructors; /// <summary> /// Instantiate a type with constructor arguments provided directly and/or from an <see cref="IServiceProvider"/>. /// </summary> /// <param name="provider">The service provider used to resolve dependencies</param> /// <param name="instanceType">The type to activate</param> /// <param name="parameters">Constructor arguments not provided by the <paramref name="provider"/>.</param> /// <returns>An activated object of type instanceType</returns> public static object CreateInstance( IServiceProvider provider, [DynamicallyAccessedMembers(ActivatorAccessibility)] Type instanceType, params object[] parameters) { var bestLength = -1; ConstructorMatcher bestMatcher = default; if (!instanceType.IsAbstract) { foreach (var constructor in instanceType.GetConstructors()) { var matcher = new ConstructorMatcher(constructor); var length = matcher.Match(parameters); if (bestLength < length) { bestLength = length; bestMatcher = matcher; } } } if (bestLength == -1) { var message = $"A suitable constructor for type '{instanceType}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."; throw new InvalidOperationException(message); } return bestMatcher.CreateInstance(provider); } /// <summary> /// Instantiate a type with constructor arguments provided directly and/or from an <see cref="IServiceProvider"/>. /// </summary> /// <typeparam name="T">The type to activate</typeparam> /// <param name="provider">The service provider used to resolve dependencies</param> /// <param name="parameters">Constructor arguments not provided by the <paramref name="provider"/>.</param> /// <returns>An activated object of type T</returns> public static T CreateInstance< [DynamicallyAccessedMembers(ActivatorAccessibility)] T >(IServiceProvider provider, params object[] parameters) { return (T)CreateInstance(provider, typeof(T), parameters); } /// <summary> /// Retrieve an instance of the given type from the service provider. If one is not found then instantiate it directly. /// </summary> /// <typeparam name="T">The type of the service</typeparam> /// <param name="provider">The service provider used to resolve dependencies</param> /// <returns>The resolved service or created instance</returns> public static T GetServiceOrCreateInstance< [DynamicallyAccessedMembers(ActivatorAccessibility)] T >(IServiceProvider provider) { return (T)GetServiceOrCreateInstance(provider, typeof(T)); } /// <summary> /// Retrieve an instance of the given type from the service provider. If one is not found then instantiate it directly. /// </summary> /// <param name="provider">The service provider</param> /// <param name="type">The type of the service</param> /// <returns>The resolved service or created instance</returns> public static object GetServiceOrCreateInstance( IServiceProvider provider, [DynamicallyAccessedMembers(ActivatorAccessibility)] Type type) { return provider.GetService(type) ?? CreateInstance(provider, type); } private struct ConstructorMatcher { private readonly ConstructorInfo _constructor; private readonly ParameterInfo[] _parameters; private readonly object?[] _parameterValues; public ConstructorMatcher(ConstructorInfo constructor) { _constructor = constructor; _parameters = _constructor.GetParameters(); _parameterValues = new object?[_parameters.Length]; } public int Match(object[] givenParameters) { var applyIndexStart = 0; var applyExactLength = 0; for (var givenIndex = 0; givenIndex != givenParameters.Length; givenIndex++) { var givenType = givenParameters[givenIndex]?.GetType(); var givenMatched = false; for (var applyIndex = applyIndexStart; givenMatched == false && applyIndex != _parameters.Length; ++applyIndex) { if (_parameterValues[applyIndex] == null && _parameters[applyIndex].ParameterType.IsAssignableFrom(givenType)) { givenMatched = true; _parameterValues[applyIndex] = givenParameters[givenIndex]; if (applyIndexStart == applyIndex) { applyIndexStart++; if (applyIndex == givenIndex) { applyExactLength = applyIndex; } } } } if (givenMatched == false) { return -1; } } return applyExactLength; } public object CreateInstance(IServiceProvider provider) { for (var index = 0; index < _parameters.Length; index++) { var parameter = _parameters[index]; if (_parameterValues[index] is null) { var value = provider.GetService(parameter.ParameterType); if (value is null) { if (!ParameterDefaultValue.TryGetDefaultValue(parameter, out var defaultValue)) { throw new InvalidOperationException($"Unable to resolve service for type '{_parameters[index].ParameterType}' while attempting to activate '{_constructor.DeclaringType}'."); } value = defaultValue; } _parameterValues[index] = value; } } #if NETCOREAPP return _constructor.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: _parameterValues, culture: null); #else try { return _constructor.Invoke(_parameterValues); } catch (TargetInvocationException ex) when (ex.InnerException != null) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); // The above line will always throw, but the compiler requires we throw explicitly. throw; } #endif } } }