From 32f16c2f247044f7cc22ed3b47fd84301041f718 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 18 Oct 2022 15:55:45 -0700 Subject: [PATCH 1/3] Adds ActivatorUtilities.CreateFactory API Fixes #34471 --- ...nsions.DependencyInjection.Abstractions.cs | 2 ++ .../src/ActivatorUtilities.cs | 29 +++++++++++++++++++ .../src/ObjectFactoryT.cs | 16 ++++++++++ .../tests/DI.Tests/ActivatorUtilitiesTests.cs | 21 ++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs 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 0d7359b076e6d..abb9b58cdbde2 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 @@ -9,6 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection public static partial class ActivatorUtilities { public static Microsoft.Extensions.DependencyInjection.ObjectFactory CreateFactory([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type instanceType, System.Type[] argumentTypes) { throw null; } + public static Microsoft.Extensions.DependencyInjection.ObjectFactory CreateFactory<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] T>(System.Type[] argumentTypes) { throw null; } public static object CreateInstance(System.IServiceProvider provider, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type instanceType, params object[] parameters) { throw null; } public static T CreateInstance<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] T>(System.IServiceProvider provider, params object[] parameters) { throw null; } public static object GetServiceOrCreateInstance(System.IServiceProvider provider, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type type) { throw null; } @@ -53,6 +54,7 @@ public partial interface ISupportRequiredService object GetRequiredService(System.Type serviceType); } public delegate object ObjectFactory(System.IServiceProvider serviceProvider, object?[]? arguments); + public delegate T ObjectFactory(System.IServiceProvider serviceProvider, object?[]? arguments); public partial class ServiceCollection : Microsoft.Extensions.DependencyInjection.IServiceCollection, System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.IEnumerable { public ServiceCollection() { } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs index 62727442fc149..6d43a77c6d3e3 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs @@ -140,6 +140,35 @@ public static ObjectFactory CreateFactory( return result.Invoke; } + /// + /// Create a delegate that will instantiate a type with constructor arguments provided directly + /// and/or from an . + /// + /// The type to activate + /// + /// The types of objects, in order, that will be passed to the returned function as its second parameter + /// + /// + /// A factory that will instantiate type T using an + /// and an argument array containing objects matching the types defined in argumentTypes + /// + public static ObjectFactory + CreateFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>( + Type[] argumentTypes) + { + FindApplicableConstructor(typeof(T), argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap); + + ParameterExpression? provider = Expression.Parameter(typeof(IServiceProvider), "provider"); + ParameterExpression? argumentArray = Expression.Parameter(typeof(object[]), "argumentArray"); + Expression? factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray); + + var factoryLambda = Expression.Lambda>( + factoryExpressionBody, provider, argumentArray); + + Func? result = factoryLambda.Compile(); + return result.Invoke; + } + /// /// Instantiate a type with constructor arguments provided directly and/or from an . /// diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs new file mode 100644 index 0000000000000..543d81793f04a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// The result of . + /// + /// The type of the instance being returned + /// The to get service arguments from. + /// Additional constructor arguments. + /// An instance of T + public delegate T ObjectFactory(IServiceProvider serviceProvider, object?[]? arguments); +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs index 3ca6e77663caa..47af6f2558de3 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs @@ -170,6 +170,27 @@ public void CreateInstance_ClassWithABC_MultipleCtorsWithSameLength_ThrowsAmbigu ActivatorUtilities.CreateInstance(provider)); Assert.Equal(message, exception.Message); } + + [Fact] + public void CreateFactory_CreatesFactoryMethod() + { + var factory1 = ActivatorUtilities.CreateFactory(typeof(ClassWithABCS), new Type[] { typeof(B) }); + var factory2 = ActivatorUtilities.CreateFactory(new Type[] { typeof(B) }); + + var services = new ServiceCollection(); + services.AddSingleton(new A()); + services.AddSingleton(new C()); + services.AddSingleton(new S()); + using var provider = services.BuildServiceProvider(); + object item1 = factory1(provider, new[] { new B() }); + var item2 = factory2(provider, new[] { new B() }); + + Assert.IsType(factory1); + Assert.IsType(item1); + + Assert.IsType>(factory2); + Assert.IsType(item2); + } } internal class A { } From d4358733ed1b1aafe647a863a130deeb09be6c1c Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 18 Oct 2022 17:02:14 -0700 Subject: [PATCH 2/3] Apply PR feedback --- .../src/ActivatorUtilities.cs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs index 6d43a77c6d3e3..0a2cb5ba943f4 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs @@ -127,11 +127,7 @@ public static ObjectFactory CreateFactory( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes) { - FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap); - - ParameterExpression? provider = Expression.Parameter(typeof(IServiceProvider), "provider"); - ParameterExpression? argumentArray = Expression.Parameter(typeof(object[]), "argumentArray"); - Expression? factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray); + CreateFactoryInternal(instanceType, argumentTypes, out ParameterExpression provider, out ParameterExpression argumentArray, out Expression factoryExpressionBody); var factoryLambda = Expression.Lambda>( factoryExpressionBody, provider, argumentArray); @@ -156,11 +152,7 @@ public static ObjectFactory CreateFactory<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>( Type[] argumentTypes) { - FindApplicableConstructor(typeof(T), argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap); - - ParameterExpression? provider = Expression.Parameter(typeof(IServiceProvider), "provider"); - ParameterExpression? argumentArray = Expression.Parameter(typeof(object[]), "argumentArray"); - Expression? factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray); + CreateFactoryInternal(typeof(T), argumentTypes, out ParameterExpression provider, out ParameterExpression argumentArray, out Expression factoryExpressionBody); var factoryLambda = Expression.Lambda>( factoryExpressionBody, provider, argumentArray); @@ -169,6 +161,15 @@ public static ObjectFactory return result.Invoke; } + private static void CreateFactoryInternal([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type instanceType, Type[] argumentTypes, out ParameterExpression provider, out ParameterExpression argumentArray, out Expression factoryExpressionBody) + { + FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap); + + provider = Expression.Parameter(typeof(IServiceProvider), "provider"); + argumentArray = Expression.Parameter(typeof(object[]), "argumentArray"); + factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray); + } + /// /// Instantiate a type with constructor arguments provided directly and/or from an . /// From 646666ef8f8fe17b1143c4728d6ffd49e2bf3f91 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Wed, 19 Oct 2022 10:55:20 -0700 Subject: [PATCH 3/3] Update src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs --- .../src/ObjectFactoryT.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs index 543d81793f04a..52ec33f8dc7cf 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ObjectFactoryT.cs @@ -6,7 +6,7 @@ namespace Microsoft.Extensions.DependencyInjection { /// - /// The result of . + /// The result of . A delegate to specify a factory method to call to instantiate an instance of type `T` /// /// The type of the instance being returned /// The to get service arguments from.