Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Breaking change]: ActivatorUtilities.CreateInstance behaves consistently independent of ctor definition order #31785

Closed
1 of 2 tasks
maryamariyan opened this issue Oct 14, 2022 · 0 comments · Fixed by #33714
Assignees
Labels
breaking-change Indicates a .NET Core breaking change 🏁 Release: .NET 8 Work items for the .NET 8 release doc-idea Indicates issues that are suggestions for new topics [org][type][category] Pri1 High priority, do before Pri2 and Pri3 📌 seQUESTered Identifies that an issue has been imported into Quest. source incompatible Source code may encounter a breaking change in behavior when targeting the new version.

Comments

@maryamariyan
Copy link
Member

maryamariyan commented Oct 14, 2022

Description

We introduced a breaking change in order to fix the bug with behavior dependence on order of constructor definition.

As part of this fix we also made the behavior of CreateInstance more coherent with CreateFactory, such that when IServiceProviderIsService is not present in the DI container then CreateInstance falls back to a CreateFactory logic, where only one constructor is allowed to match with all the required given input parameters.

In a more general case when we expect IServiceProviderIsService to be present, the CreateInstance API prefers the longest constructor overload that has all its arguments either available as input to the API or as registered in the container or available with default values to the constructor itself.

Example:

public class A
{
   A(B b, C c, string st = "default string") { }
   A() { }
}

For the above class definition, with IServiceProviderIsService, the expectation is for ActivatorUtilities.CreateInstance<A>(serviceProvider, new C()) to instantiate A by picking the first constructor taking B, C and string.

Version

.NET 8 Preview 1

Previous behavior

ActivatorUtilities.CreateInstance had cases where it behaved unexpectedly.

The API would make sure all required instances passed to it exist in the constructor being picked. But the constructor selection was buggy and not reliable.

New behavior

General idea:

CreateInstance tries to find the longest constructor matching all parameters based on the behavior of IServiceProviderIsService.
If none are found, try to fallback to CreateFactory, if it finds more than one constructor it throws
if IServiceProviderIsService is not present it falls back to CreateFactory logic.
If IServiceProviderIsService is configured wrong, or does not exist, it is OK for the API to function incorrectly or ambiguously.

Type of breaking change

  • Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load/execute or different run-time behavior.
  • Source incompatible: Source code may encounter a breaking change in behavior when targeting the new runtime/component/SDK, such as compile errors or different run-time behavior.

Reason for change

To fix the bug with inconsistent behavior when constructor overload definition order changes

Recommended action

Carefully examine constructor definitions if for the given instance type if you are suddenly getting failure now after updating to .NET 8 Preview 1. (Refer to new behavior above).

Feature area

C#, Core .NET libraries, Extensions

Affected APIs

ActivatorUtilities.CreateInstance

Fixed in PR dotnet/runtime#75846


Associated WorkItem - 60828

@maryamariyan maryamariyan added doc-idea Indicates issues that are suggestions for new topics [org][type][category] breaking-change Indicates a .NET Core breaking change Pri1 High priority, do before Pri2 and Pri3 labels Oct 14, 2022
@dotnet-bot dotnet-bot added ⌚ Not Triaged Not triaged source incompatible Source code may encounter a breaking change in behavior when targeting the new version. labels Oct 14, 2022
@gewarren gewarren added 🏁 Release: .NET 8 Work items for the .NET 8 release and removed ⌚ Not Triaged Not triaged labels Oct 24, 2022
@gewarren gewarren added the 🗺️ reQUEST Triggers an issue to be imported into Quest. label Jan 10, 2023
@ghost ghost added the in-pr This issue will be closed (fixed) by an active pull request. label Jan 25, 2023
@github-actions github-actions bot added 📌 seQUESTered Identifies that an issue has been imported into Quest. and removed 🗺️ reQUEST Triggers an issue to be imported into Quest. labels Jan 25, 2023
@ghost ghost removed the in-pr This issue will be closed (fixed) by an active pull request. label Mar 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Indicates a .NET Core breaking change 🏁 Release: .NET 8 Work items for the .NET 8 release doc-idea Indicates issues that are suggestions for new topics [org][type][category] Pri1 High priority, do before Pri2 and Pri3 📌 seQUESTered Identifies that an issue has been imported into Quest. source incompatible Source code may encounter a breaking change in behavior when targeting the new version.
Projects
No open projects
Status: 🏗 In progress
Development

Successfully merging a pull request may close this issue.

3 participants