-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
ActivatorUtilities - matching preferred constructor depends on the constructors order #98959
Comments
Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection Issue DetailsDescriptionSelecting the preferred constructor by Reproduction StepsLet's consider the following class:
Let's assume that I want to instantiate this class using the Dependency Injection container:
This obviously fails because
This still throws the same error. Expected behaviorIf Actual behaviorI have digged in the source code and I think the reason is a mistake in
If the constructors appeared in an opposite order the condition in line Regression?No response Known WorkaroundsAdd the constructor decorated with ConfigurationNo response Other informationNo response
|
Verified repro on v7 - v9P1. |
Thanks @steveharter for verifying. Is there a chance that it can get fixed in the future releases of v8 as well? On the other side I can imagine that as this would change the behavior of the runtime it could be considered to be a breaking change in some cases... |
I looked at this in greater detail: Calling Only ActivatorUtilities.CreateInstance() checks for However, changing your repro to use
instead of
still results in the same issue - the ordering of the constructors affects the check for |
I assume the semantics of
@tarekgh does this sound correct? I may push a PR soon that does this. |
Mostly correct. The following comment describing it: The only difference is, when seeing a constructor with CC @eerhardt |
Reflection will return the constructors in the order they are defined. However it looks like ctor lookup from GetService() does order the constructors.
So reflection ordering does matter then. That doesn't seem like a good thing IMO. In either case, I will still put up a PR to address the case where ordering with the same number of parameters doesn't always respect Aside, ideally, it seems like |
Moving to V10; this area is still broke and\or confusing. The DI GetService() does not use the attribute - see #98959 (comment). |
Does anybody know why the semantics between We have a few places in our application that rely on This always felt like a poor design to me. Feels like there shouldn't be any difference in activating a registered type, vs constructing an unregistered one as long as you didn't register a construction lambda in the registration. Both operations are semantically identical. |
That is what @steveharter tracking to fix. We are keeping this issue open to address that. |
Description
Selecting the preferred constructor by
ActivatorUtilitiesConstructor
attribute works differently depending on the order of constructors.Reproduction Steps
Let's consider the following class:
Let's assume that I want to instantiate this class using the Dependency Injection container:
This obviously fails because
ActivatorUtilities
class finds two matching constructors.Fortunately there is a
[ActivatorUtilitiesConstructorAttribute](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilitiesConstructorAttribute.cs)
so let's adjust the classFoo
:This still throws the same error.
Expected behavior
If
[ActivatorUtilitiesConstructor]
is used the constructor should be prioritized above all other constructors if all its dependencies are satisfied, regardless of the order of the constructors in the source code.Actual behavior
I have digged in the source code and I think the reason is a mistake in
ActivatorUtilities
class.The following snippet of code (https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs#L95)
isPreferred
is properly set to true based on the existance of the attribute on the first constructor. But when the second constructor (public Foo(Baz baz)
) is analyzed the condition in line 108 (if (isPreferred || bestLength < length)
) isfalse
, but the else statement in line 114 (else if (bestLength == length)
) is evaluated totrue
and therefore the constructor is also considered to be the best candidate.If the constructors appeared in an opposite order the condition in line
108
would be true and the code would have worked properly.Regression?
No response
Known Workarounds
Add the constructor decorated with
ActivatorUtilitiesConstructorAttribute
after all other constructors in your class.Configuration
No response
Other information
No response
The text was updated successfully, but these errors were encountered: