ActivatorUtilities.CreateInstance behaves consistently
The behavior of ActivatorUtilities.CreateInstance is now more consistent with CreateFactory(Type, Type[]). When IServiceProviderIsService isn't present in the dependency injection (DI) container, CreateInstance falls back to the CreateFactory(Type, Type[]) logic. In that logic, only one constructor is allowed to match with all the provided input parameters.
In the more general case when IServiceProviderIsService is present, the CreateInstance
API prefers the longest constructor overload that has all its arguments available. The arguments can be input to the API, registered in the container, or available from default values in the constructor itself.
Consider the following class definition showing two constructors:
public class A
{
A(B b, C c, string st = "default string") { }
A() { }
}
For this class definition, and when IServiceProviderIsService
is present, ActivatorUtilities.CreateInstance<A>(serviceProvider, new C())
instantiates A
by picking the first constructor that takes B
, C
, and string
.
Version introduced
.NET 8 Preview 1
Previous behavior
ActivatorUtilities.CreateInstance behaved unexpectedly in some cases. It made sure all required instances passed to it existed in the chosen constructor. However, the constructor selection was buggy and unreliable.
New behavior
CreateInstance tries to find the longest constructor that matches all parameters based on the behavior of IServiceProviderIsService.
- If no constructors are found or if IServiceProviderIsService isn't present, it falls back to CreateFactory(Type, Type[]) logic.
- If it finds more than one constructor, it throws an InvalidOperationException.
Note
If IServiceProviderIsService is configured incorrectly or doesn't exist, CreateInstance
may function incorrectly or ambiguously.
Type of breaking change
This change is a behavioral change.
Reason for change
This change was introduced to fix a bug where the behavior changed depending on the order of constructor overload definitions.
Recommended action
If your app starts behaving differently or throwing an exception after upgrading to .NET 8, carefully examine the constructor definitions for the affected instance type. Refer to the New behavior section.
Affected APIs
- Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance<T>(IServiceProvider, Object[])
- Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider, Type, Object[])