Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bb919c2

Browse files
authored
ActivatorUtilities.CreateInstance() should respect [ActivatorUtilitiesConstructor] (#99175)
1 parent 79a1c91 commit bb919c2

File tree

2 files changed

+204
-7
lines changed

2 files changed

+204
-7
lines changed

src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,25 @@ public static object CreateInstance(
103103
{
104104
ThrowMarkedCtorDoesNotTakeAllProvidedArguments();
105105
}
106-
}
107106

108-
if (isPreferred || bestLength < length)
109-
{
107+
seenPreferred = true;
110108
bestLength = length;
111109
bestMatcher = matcher;
112110
multipleBestLengthFound = false;
113111
}
114-
else if (bestLength == length)
112+
else if (!seenPreferred)
115113
{
116-
multipleBestLengthFound = true;
114+
if (bestLength < length)
115+
{
116+
bestLength = length;
117+
bestMatcher = matcher;
118+
multipleBestLengthFound = false;
119+
}
120+
else if (bestLength == length)
121+
{
122+
multipleBestLengthFound = true;
123+
}
117124
}
118-
119-
seenPreferred |= isPreferred;
120125
}
121126

122127
if (bestLength != -1)

src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,96 @@ public void CreateInstance_ClassWithABC_ConstructorWithAttribute_PicksCtorWithAt
170170
Assert.Same(a, instance.A);
171171
}
172172

173+
[Fact]
174+
public void CreateInstanceFailsWithAmbiguousConstructor()
175+
{
176+
var serviceCollection = new ServiceCollection();
177+
serviceCollection.AddTransient<ClassWithA_And_B>();
178+
serviceCollection.AddTransient<A>();
179+
serviceCollection.AddTransient<B>();
180+
181+
var serviceProvider = serviceCollection.BuildServiceProvider();
182+
183+
// Neither ctor(A) nor ctor(B) have [ActivatorUtilitiesConstructor].
184+
Assert.Throws<InvalidOperationException>(() => ActivatorUtilities.CreateInstance<ClassWithA_And_B>(serviceProvider));
185+
}
186+
187+
[Fact]
188+
public void CreateInstanceFailsWithAmbiguousConstructor_ReversedOrder()
189+
{
190+
var serviceCollection = new ServiceCollection();
191+
serviceCollection.AddTransient<ClassWithB_And_A>();
192+
serviceCollection.AddTransient<A>();
193+
serviceCollection.AddTransient<B>();
194+
195+
var serviceProvider = serviceCollection.BuildServiceProvider();
196+
197+
// Neither ctor(A) nor ctor(B) have [ActivatorUtilitiesConstructor].
198+
Assert.Throws<InvalidOperationException>(() => ActivatorUtilities.CreateInstance<ClassWithA_And_B>(serviceProvider));
199+
}
200+
201+
[Fact]
202+
public void CreateInstancePassesWithAmbiguousConstructor()
203+
{
204+
var serviceCollection = new ServiceCollection();
205+
serviceCollection.AddTransient<ClassWithA_And_B_ActivatorUtilitiesConstructorAttribute>();
206+
serviceCollection.AddTransient<A>();
207+
serviceCollection.AddTransient<B>();
208+
209+
var serviceProvider = serviceCollection.BuildServiceProvider();
210+
var service = ActivatorUtilities.CreateInstance<ClassWithA_And_B_ActivatorUtilitiesConstructorAttribute>(serviceProvider);
211+
212+
// Ensure ctor(A) was selected over ctor(B) since A has [ActivatorUtilitiesConstructor].
213+
Assert.NotNull(service.A);
214+
}
215+
216+
[Fact]
217+
public void CreateInstancePassesWithAmbiguousConstructor_ReversedOrder()
218+
{
219+
var serviceCollection = new ServiceCollection();
220+
serviceCollection.AddTransient<ClassWithB_And_A_ActivatorUtilitiesConstructorAttribute>();
221+
serviceCollection.AddTransient<A>();
222+
serviceCollection.AddTransient<B>();
223+
224+
var serviceProvider = serviceCollection.BuildServiceProvider();
225+
var service = ActivatorUtilities.CreateInstance<ClassWithB_And_A_ActivatorUtilitiesConstructorAttribute>(serviceProvider);
226+
227+
// Ensure ctor(A) was selected over ctor(B) since A has [ActivatorUtilitiesConstructor].
228+
Assert.NotNull(service.A);
229+
}
230+
231+
[Fact]
232+
public void CreateInstanceIgnoresActivatorUtilitiesConstructorAttribute()
233+
{
234+
var serviceCollection = new ServiceCollection();
235+
serviceCollection.AddTransient<ClassWithA_And_AB_ActivatorUtilitiesConstructorAttribute>();
236+
serviceCollection.AddTransient<A>();
237+
serviceCollection.AddTransient<B>();
238+
239+
var serviceProvider = serviceCollection.BuildServiceProvider();
240+
var service = ActivatorUtilities.CreateInstance<ClassWithA_And_AB_ActivatorUtilitiesConstructorAttribute>(serviceProvider);
241+
242+
// Ensure ctor(A) was selected since A has [ActivatorUtilitiesConstructor].
243+
Assert.NotNull(service.A);
244+
Assert.Null(service.B);
245+
}
246+
247+
[Fact]
248+
public void CreateInstanceIgnoresActivatorUtilitiesConstructorAttribute_ReversedOrder()
249+
{
250+
var serviceCollection = new ServiceCollection();
251+
serviceCollection.AddTransient<ClassWithAB_And_A_ActivatorUtilitiesConstructorAttribute>();
252+
serviceCollection.AddTransient<A>();
253+
serviceCollection.AddTransient<B>();
254+
255+
var serviceProvider = serviceCollection.BuildServiceProvider();
256+
var service = ActivatorUtilities.CreateInstance<ClassWithAB_And_A_ActivatorUtilitiesConstructorAttribute>(serviceProvider);
257+
258+
// Ensure ctor(A) was selected since it has [ActivatorUtilitiesConstructor].
259+
Assert.NotNull(service.A);
260+
Assert.Null(service.B);
261+
}
262+
173263
[Fact]
174264
public void CreateInstance_ClassWithABC_MultipleCtorsWithSameLength_ThrowsAmbiguous()
175265
{
@@ -662,6 +752,108 @@ public ClassWithABC_LastConstructorWithAttribute(B b, C c) : this(null, b, c) {
662752
public ClassWithABC_LastConstructorWithAttribute(A a, B b, C c) : base(a, b, c) { }
663753
}
664754

755+
internal class ClassWithA_And_B
756+
{
757+
public ClassWithA_And_B(A a)
758+
{
759+
A = a;
760+
}
761+
762+
public ClassWithA_And_B(B b)
763+
{
764+
B = b;
765+
}
766+
767+
public A A { get; }
768+
public B B { get; }
769+
}
770+
771+
internal class ClassWithB_And_A
772+
{
773+
public ClassWithB_And_A(A a)
774+
{
775+
A = a;
776+
}
777+
778+
public ClassWithB_And_A(B b)
779+
{
780+
B = b;
781+
}
782+
783+
public A A { get; }
784+
public B B { get; }
785+
}
786+
787+
internal class ClassWithA_And_B_ActivatorUtilitiesConstructorAttribute
788+
{
789+
[ActivatorUtilitiesConstructor]
790+
public ClassWithA_And_B_ActivatorUtilitiesConstructorAttribute(A a)
791+
{
792+
A = a;
793+
}
794+
795+
public ClassWithA_And_B_ActivatorUtilitiesConstructorAttribute(B b)
796+
{
797+
B = b;
798+
}
799+
800+
public A A { get; }
801+
public B B { get; }
802+
}
803+
804+
internal class ClassWithB_And_A_ActivatorUtilitiesConstructorAttribute
805+
{
806+
public ClassWithB_And_A_ActivatorUtilitiesConstructorAttribute(B b)
807+
{
808+
B = b;
809+
}
810+
811+
[ActivatorUtilitiesConstructor]
812+
public ClassWithB_And_A_ActivatorUtilitiesConstructorAttribute(A a)
813+
{
814+
A = a;
815+
}
816+
817+
public A A { get; }
818+
public B B { get; }
819+
}
820+
821+
internal class ClassWithA_And_AB_ActivatorUtilitiesConstructorAttribute
822+
{
823+
[ActivatorUtilitiesConstructor]
824+
public ClassWithA_And_AB_ActivatorUtilitiesConstructorAttribute(A a)
825+
{
826+
A = a;
827+
}
828+
829+
public ClassWithA_And_AB_ActivatorUtilitiesConstructorAttribute(A a, B b)
830+
{
831+
A = a;
832+
B = b;
833+
}
834+
835+
public A A { get; }
836+
public B B { get; }
837+
}
838+
839+
internal class ClassWithAB_And_A_ActivatorUtilitiesConstructorAttribute
840+
{
841+
public ClassWithAB_And_A_ActivatorUtilitiesConstructorAttribute(A a, B b)
842+
{
843+
A = a;
844+
B = b;
845+
}
846+
847+
[ActivatorUtilitiesConstructor]
848+
public ClassWithAB_And_A_ActivatorUtilitiesConstructorAttribute(A a)
849+
{
850+
A = a;
851+
}
852+
853+
public A A { get; }
854+
public B B { get; }
855+
}
856+
665857
internal class FakeServiceProvider : IServiceProvider
666858
{
667859
private IServiceProvider _inner;

0 commit comments

Comments
 (0)