Reputation: 81
I am new to .NET core and I want to start a project using it. I have been reading official documentation and tutorials.
In the Microsoft official documentation about dependency injection, in the section of "Constructor injection behavior", it has been explained that "When services are resolved by ActivatorUtilities
, constructor injection requires that only one applicable constructor exists. Constructor overloads are supported, but only one overload can exist whose arguments can all be fulfilled by dependency injection."
In that statement what they mean by "only one applicable constructor exists"? Could anyone please explain. If there are only one, how it supports constructor overloading. It is bit confusing to me.
PS:- Feel free to down-vote, but please be kind enough to mention where should I ask this question, in the comments section if this question doesn't match the criteria.
Upvotes: 0
Views: 656
Reputation: 155135
It means that when you have a class that uses DI, it must have exactly one constructor where all parameters are either registered dependencies (or services) or have default values.
I note that the documentation doesn't say what happens if it does but I assume it will throw an exception or fail somehow (e.g. the factory method returning null
?)
The documentation also states:
Constructors can accept arguments that aren't provided by dependency injection, but the arguments must assign default values.
By example - if we have a DI context where these services are available:
IImageResizerService
IImageSavingService
IImageObjectRecognizerService
public class DefaultImageProcessingService : IImageProcessingService
{
public DefaultImageProcessingService
(
IImageResizerService resizer,
IImageSavingService saver,
IImageObjectRecognizerService recognizer,
String defaultFileName = null,
Int32 maxSaveAttempts = 3
)
{
this.resizer = resizer ?? throw new ArgumentNullException( nameof(resizer) );
this.saver = saver ?? throw new ArgumentNullException( nameof(saver) );
this.recognizer = recognizer?? throw new ArgumentNullException( nameof(recognizer) );
}
}
public class DefaultImageProcessingService : IImageProcessingService
{
public DefaultImageProcessingService
(
IImageResizerService resizer,
String defaultFileName = null,
Int32 maxSaveAttempts = 3
)
{
this.resizer = resizer ?? throw new ArgumentNullException( nameof(resizer) );
}
public DefaultImageProcessingService
(
IImageSavingService saver,
IImageObjectRecognizerService recognizer,
String defaultFileName = null,
Int32 maxSaveAttempts = 3
)
{
this.saver = saver ?? throw new ArgumentNullException( nameof(saver) );
this.recognizer = recognizer?? throw new ArgumentNullException( nameof(recognizer) );
}
}
It isn't acceptable because it has two constructors that both have registered services as parameters. So the DI factory doesn't know which constructor to use because it could use either of them.
public class DefaultImageProcessingService : IImageProcessingService
{
public DefaultImageProcessingService
(
IImageResizerService resizer,
IImageSavingService saver,
IImageObjectRecognizerService recognizer,
IMysteryService mystery,
String defaultFileName = null,
Int32 maxSaveAttempts = 3
)
{
this.resizer = resizer ?? throw new ArgumentNullException( nameof(resizer) );
this.saver = saver ?? throw new ArgumentNullException( nameof(saver) );
this.recognizer = recognizer ?? throw new ArgumentNullException( nameof(recognizer) );
this.mystery = mystery ?? throw new ArgumentNullException( nameof(mystery) );
}
}
It isn't acceptable because IMysteryService
is not registered.
public class DefaultImageProcessingService : IImageProcessingService
{
public DefaultImageProcessingService
(
IImageResizerService resizer,
IImageSavingService saver,
IImageObjectRecognizerService recognizer,
String defaultFileName = null,
Int32 maxSaveAttempts = 3
)
{
this.resizer = resizer ?? throw new ArgumentNullException( nameof(resizer) );
this.saver = saver ?? throw new ArgumentNullException( nameof(saver) );
this.recognizer = recognizer?? throw new ArgumentNullException( nameof(recognizer) );
}
public DefaultImageProcessingService
(
IImageResizerService resizer,
IImageSavingService saver,
IImageObjectRecognizerService recognizer,
IMysteryService mystery,
String defaultFileName = null,
Int32 maxSaveAttempts = 3
)
{
this.resizer = resizer ?? throw new ArgumentNullException( nameof(resizer) );
this.saver = saver ?? throw new ArgumentNullException( nameof(saver) );
this.recognizer = recognizer ?? throw new ArgumentNullException( nameof(recognizer) );
this.mystery = mystery ?? throw new ArgumentNullException( nameof(mystery) );
}
}
It's acceptable because one of the constructors is only uses registered services and default values (the first constructor). The second constructor will not be used by the DI factory because it has a non-satisfiable parameter (IMysteryService
).
Upvotes: 1