From 7f63fe5e7d61a408a72cf168300af8eb4545170d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 5 Jun 2020 08:17:56 -0700 Subject: [PATCH 1/5] Annotate Microsoft.Extensions.DependencyInjection.Abstractions for nullable reference types Contributes to https://github.com/dotnet/runtime/issues/2339 --- .../ActivatorUtilities/ActivatorUtilities.cs | 27 ++++++++++--------- .../ParameterDefaultValue.cs | 3 ++- ...nsions.DependencyInjection.Abstractions.cs | 6 ++--- ...ns.DependencyInjection.Abstractions.csproj | 1 + ...ns.DependencyInjection.Abstractions.csproj | 1 + .../src/ServiceDescriptor.cs | 6 ++--- .../src/ServiceProviderServiceExtensions.cs | 3 +++ 7 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs index c4c20f1fba3b40..3ce76dea29d401 100644 --- a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -30,7 +31,7 @@ namespace Microsoft.Extensions.Internal static class ActivatorUtilities { private static readonly MethodInfo GetServiceInfo = - GetMethodInfo>((sp, t, r, c) => GetService(sp, t, r, c)); + GetMethodInfo>((sp, t, r, c) => GetService(sp, t, r, c)); /// /// Instantiate a type with constructor arguments provided directly and/or from an . @@ -105,7 +106,7 @@ public static object CreateInstance(IServiceProvider provider, Type instanceType /// public static ObjectFactory CreateFactory(Type instanceType, Type[] argumentTypes) { - FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap); + FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo? constructor, out int?[]? parameterMap); var provider = Expression.Parameter(typeof(IServiceProvider), "provider"); var argumentArray = Expression.Parameter(typeof(object[]), "argumentArray"); @@ -159,7 +160,7 @@ private static MethodInfo GetMethodInfo(Expression expr) return mc.Method; } - private static object GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired) + private static object? GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired) { var service = sp.GetService(type); if (service == null && !isDefaultParameterRequired) @@ -215,8 +216,8 @@ private static Expression BuildFactoryExpression( private static void FindApplicableConstructor( Type instanceType, Type[] argumentTypes, - out ConstructorInfo matchingConstructor, - out int?[] parameterMap) + [NotNull] out ConstructorInfo? matchingConstructor, + [NotNull] out int?[]? parameterMap) { matchingConstructor = null; parameterMap = null; @@ -233,8 +234,8 @@ private static void FindApplicableConstructor( private static bool TryFindMatchingConstructor( Type instanceType, Type[] argumentTypes, - ref ConstructorInfo matchingConstructor, - ref int?[] parameterMap) + [NotNullWhen(true)] ref ConstructorInfo? matchingConstructor, + [NotNullWhen(true)] ref int?[]? parameterMap) { foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors) { @@ -255,15 +256,15 @@ private static bool TryFindMatchingConstructor( } } - return matchingConstructor != null; + return matchingConstructor != null && parameterMap != null; } // Tries to find constructor marked with ActivatorUtilitiesConstructorAttribute private static bool TryFindPreferredConstructor( Type instanceType, Type[] argumentTypes, - ref ConstructorInfo matchingConstructor, - ref int?[] parameterMap) + [NotNullWhen(true)] ref ConstructorInfo? matchingConstructor, + [NotNullWhen(true)] ref int?[]? parameterMap) { var seenPreferred = false; foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors) @@ -291,7 +292,7 @@ private static bool TryFindPreferredConstructor( } } - return matchingConstructor != null; + return matchingConstructor != null && parameterMap != null; } // Creates an injective parameterMap from givenParameterTypes to assignable constructorParameters. @@ -334,13 +335,13 @@ private struct ConstructorMatcher { private readonly ConstructorInfo _constructor; private readonly ParameterInfo[] _parameters; - private readonly object[] _parameterValues; + private readonly object?[] _parameterValues; public ConstructorMatcher(ConstructorInfo constructor) { _constructor = constructor; _parameters = _constructor.GetParameters(); - _parameterValues = new object[_parameters.Length]; + _parameterValues = new object?[_parameters.Length]; } public int Match(object[] givenParameters) diff --git a/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs b/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs index c55b7a3cb7fca9..dac476d32d9c5b 100644 --- a/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs +++ b/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs @@ -5,13 +5,14 @@ using System; using System.Reflection; +#nullable enable namespace Microsoft.Extensions.Internal { internal class ParameterDefaultValue { private static readonly Type _nullable = typeof(Nullable<>); - public static bool TryGetDefaultValue(ParameterInfo parameter, out object defaultValue) + public static bool TryGetDefaultValue(ParameterInfo parameter, out object? defaultValue) { bool hasDefaultValue; var tryToGetDefaultValue = true; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 733838e7e5f223..1bd3edec822a81 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -71,9 +71,9 @@ public partial class ServiceDescriptor public ServiceDescriptor(System.Type serviceType, System.Func factory, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { } public ServiceDescriptor(System.Type serviceType, object instance) { } public ServiceDescriptor(System.Type serviceType, System.Type implementationType, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { } - public System.Func ImplementationFactory { get { throw null; } } - public object ImplementationInstance { get { throw null; } } - public System.Type ImplementationType { get { throw null; } } + public System.Func? ImplementationFactory { get { throw null; } } + public object? ImplementationInstance { get { throw null; } } + public System.Type? ImplementationType { get { throw null; } } public Microsoft.Extensions.DependencyInjection.ServiceLifetime Lifetime { get { throw null; } } public System.Type ServiceType { get { throw null; } } public static Microsoft.Extensions.DependencyInjection.ServiceDescriptor Describe(System.Type serviceType, System.Func implementationFactory, Microsoft.Extensions.DependencyInjection.ServiceLifetime lifetime) { throw null; } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj index 0adff566b0bfd4..942dbe0ee15295 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj @@ -1,6 +1,7 @@ netstandard2.0 + enable diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj index 167a6ebd19e972..17654fa1889d07 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj @@ -4,6 +4,7 @@ netstandard2.0 $(DefineConstants);ActivatorUtilities_In_DependencyInjection true + enable diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs index bb850efe12facd..409aa6da34af5e 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs @@ -100,13 +100,13 @@ private ServiceDescriptor(Type serviceType, ServiceLifetime lifetime) public Type ServiceType { get; } /// - public Type ImplementationType { get; } + public Type? ImplementationType { get; } /// - public object ImplementationInstance { get; } + public object? ImplementationInstance { get; } /// - public Func ImplementationFactory { get; } + public Func? ImplementationFactory { get; } /// public override string ToString() diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs index 1a7ffad12ad7d8..0aa315e89259ab 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.DependencyInjection { @@ -18,6 +19,7 @@ public static class ServiceProviderServiceExtensions /// The type of service object to get. /// The to retrieve the service object from. /// A service object of type or null if there is no such service. + [return: MaybeNull] public static T GetService(this IServiceProvider provider) { if (provider == null) @@ -69,6 +71,7 @@ public static object GetRequiredService(this IServiceProvider provider, Type ser /// The to retrieve the service object from. /// A service object of type . /// There is no service of type . + [return: NotNull] public static T GetRequiredService(this IServiceProvider provider) { if (provider == null) From 3c1e02433dce1dc97d6bc320b0912abe51cd32f4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 8 Jun 2020 23:01:23 -0700 Subject: [PATCH 2/5] PR feeedback --- .../ParameterDefaultValue/ParameterDefaultValue.cs | 3 ++- ...Microsoft.Extensions.DependencyInjection.Abstractions.cs | 6 +++--- .../src/IServiceProviderFactory.cs | 2 +- .../src/ServiceProviderServiceExtensions.cs | 5 ++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs b/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs index dac476d32d9c5b..abcbf454dcfa5a 100644 --- a/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs +++ b/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs @@ -2,10 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + using System; using System.Reflection; -#nullable enable namespace Microsoft.Extensions.Internal { internal class ParameterDefaultValue diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 1bd3edec822a81..5c03f2564ff8de 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -22,7 +22,7 @@ public ActivatorUtilitiesConstructorAttribute() { } public partial interface IServiceCollection : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.IEnumerable { } - public partial interface IServiceProviderFactory + public partial interface IServiceProviderFactory where TContainerBuilder : notnull { TContainerBuilder CreateBuilder(Microsoft.Extensions.DependencyInjection.IServiceCollection services); System.IServiceProvider CreateServiceProvider(TContainerBuilder containerBuilder); @@ -107,8 +107,8 @@ public static partial class ServiceProviderServiceExtensions { public static Microsoft.Extensions.DependencyInjection.IServiceScope CreateScope(this System.IServiceProvider provider) { throw null; } public static object GetRequiredService(this System.IServiceProvider provider, System.Type serviceType) { throw null; } - public static T GetRequiredService(this System.IServiceProvider provider) { throw null; } - public static System.Collections.Generic.IEnumerable GetServices(this System.IServiceProvider provider, System.Type serviceType) { throw null; } + public static T GetRequiredService(this System.IServiceProvider provider) where T : notnull { throw null; } + public static System.Collections.Generic.IEnumerable GetServices(this System.IServiceProvider provider, System.Type serviceType) { throw null; } public static System.Collections.Generic.IEnumerable GetServices(this System.IServiceProvider provider) { throw null; } public static T GetService(this System.IServiceProvider provider) { throw null; } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceProviderFactory.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceProviderFactory.cs index 0d0a66bab676ab..a8b71bce3db761 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceProviderFactory.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceProviderFactory.cs @@ -9,7 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection /// /// Provides an extension point for creating a container specific builder and an . /// - public interface IServiceProviderFactory + public interface IServiceProviderFactory where TContainerBuilder : notnull { /// /// Creates a container builder from an . diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs index 0aa315e89259ab..830009056e57ac 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs @@ -71,8 +71,7 @@ public static object GetRequiredService(this IServiceProvider provider, Type ser /// The to retrieve the service object from. /// A service object of type . /// There is no service of type . - [return: NotNull] - public static T GetRequiredService(this IServiceProvider provider) + public static T GetRequiredService(this IServiceProvider provider) where T : notnull { if (provider == null) { @@ -104,7 +103,7 @@ public static IEnumerable GetServices(this IServiceProvider provider) /// The to retrieve the services from. /// An object that specifies the type of service object to get. /// An enumeration of services of type . - public static IEnumerable GetServices(this IServiceProvider provider, Type serviceType) + public static IEnumerable GetServices(this IServiceProvider provider, Type serviceType) { if (provider == null) { From f5d70a637a483b082c5ea1359d462a2442f7f9ba Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Jun 2020 07:27:08 -0700 Subject: [PATCH 3/5] Undo changes to ActivatorUtils implementation --- .../ActivatorUtilities/ActivatorUtilities.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs index 3ce76dea29d401..c77c5d5b8274d2 100644 --- a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs @@ -217,7 +217,7 @@ private static void FindApplicableConstructor( Type instanceType, Type[] argumentTypes, [NotNull] out ConstructorInfo? matchingConstructor, - [NotNull] out int?[]? parameterMap) + out int?[]? parameterMap) { matchingConstructor = null; parameterMap = null; @@ -235,7 +235,7 @@ private static bool TryFindMatchingConstructor( Type instanceType, Type[] argumentTypes, [NotNullWhen(true)] ref ConstructorInfo? matchingConstructor, - [NotNullWhen(true)] ref int?[]? parameterMap) + ref int?[]? parameterMap) { foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors) { @@ -256,7 +256,7 @@ private static bool TryFindMatchingConstructor( } } - return matchingConstructor != null && parameterMap != null; + return matchingConstructor != null; } // Tries to find constructor marked with ActivatorUtilitiesConstructorAttribute @@ -264,7 +264,7 @@ private static bool TryFindPreferredConstructor( Type instanceType, Type[] argumentTypes, [NotNullWhen(true)] ref ConstructorInfo? matchingConstructor, - [NotNullWhen(true)] ref int?[]? parameterMap) + ref int?[]? parameterMap) { var seenPreferred = false; foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors) @@ -292,7 +292,7 @@ private static bool TryFindPreferredConstructor( } } - return matchingConstructor != null && parameterMap != null; + return matchingConstructor != null; } // Creates an injective parameterMap from givenParameterTypes to assignable constructorParameters. From 3c24f6bf30866c53ef12008ff5e77cf00d0b9318 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 9 Jun 2020 18:43:53 -0700 Subject: [PATCH 4/5] Fixups --- .../ActivatorUtilities/ActivatorUtilities.cs | 23 +++++++++++++++---- ...nsions.DependencyInjection.Abstractions.cs | 1 + 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs index c77c5d5b8274d2..b7e97e3f91fe6f 100644 --- a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; @@ -217,7 +218,7 @@ private static void FindApplicableConstructor( Type instanceType, Type[] argumentTypes, [NotNull] out ConstructorInfo? matchingConstructor, - out int?[]? parameterMap) + [NotNull] out int?[]? parameterMap) { matchingConstructor = null; parameterMap = null; @@ -235,7 +236,7 @@ private static bool TryFindMatchingConstructor( Type instanceType, Type[] argumentTypes, [NotNullWhen(true)] ref ConstructorInfo? matchingConstructor, - ref int?[]? parameterMap) + [NotNullWhen(true)] ref int?[]? parameterMap) { foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors) { @@ -256,7 +257,13 @@ private static bool TryFindMatchingConstructor( } } - return matchingConstructor != null; + if (matchingConstructor != null) + { + Debug.Assert(parameterMap != null); + return true; + } + + return false; } // Tries to find constructor marked with ActivatorUtilitiesConstructorAttribute @@ -264,7 +271,7 @@ private static bool TryFindPreferredConstructor( Type instanceType, Type[] argumentTypes, [NotNullWhen(true)] ref ConstructorInfo? matchingConstructor, - ref int?[]? parameterMap) + [NotNullWhen(true)] ref int?[]? parameterMap) { var seenPreferred = false; foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors) @@ -292,7 +299,13 @@ private static bool TryFindPreferredConstructor( } } - return matchingConstructor != null; + if (matchingConstructor != null) + { + Debug.Assert(parameterMap != null); + return true; + } + + return false; } // Creates an injective parameterMap from givenParameterTypes to assignable constructorParameters. diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 5c03f2564ff8de..aac4f5d2c027d5 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -110,6 +110,7 @@ public static partial class ServiceProviderServiceExtensions public static T GetRequiredService(this System.IServiceProvider provider) where T : notnull { throw null; } public static System.Collections.Generic.IEnumerable GetServices(this System.IServiceProvider provider, System.Type serviceType) { throw null; } public static System.Collections.Generic.IEnumerable GetServices(this System.IServiceProvider provider) { throw null; } + [return: System.Diagnostics.CodeAnalysis.MaybeNullAttribute] public static T GetService(this System.IServiceProvider provider) { throw null; } } } From b2d87efb10587cdc9f3de5d8d500a96b87425df0 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 11 Jun 2020 06:41:23 -0700 Subject: [PATCH 5/5] Remove NotNull --- .../ActivatorUtilities/ActivatorUtilities.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs index b7e97e3f91fe6f..2c397dcd075211 100644 --- a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs @@ -217,18 +217,21 @@ private static Expression BuildFactoryExpression( private static void FindApplicableConstructor( Type instanceType, Type[] argumentTypes, - [NotNull] out ConstructorInfo? matchingConstructor, - [NotNull] out int?[]? parameterMap) + out ConstructorInfo matchingConstructor, + out int?[] matchingParameterMap) { - matchingConstructor = null; - parameterMap = null; + ConstructorInfo? constructorInfo = null; + int?[]? parameterMap = null; - if (!TryFindPreferredConstructor(instanceType, argumentTypes, ref matchingConstructor, ref parameterMap) && - !TryFindMatchingConstructor(instanceType, argumentTypes, ref matchingConstructor, ref parameterMap)) + if (!TryFindPreferredConstructor(instanceType, argumentTypes, ref constructorInfo, ref parameterMap) && + !TryFindMatchingConstructor(instanceType, argumentTypes, ref constructorInfo, ref parameterMap)) { 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); } + + matchingConstructor = constructorInfo; + matchingParameterMap = parameterMap; } // Tries to find constructor based on provided argument types