Implémente le principe de l'Inversion of Control.
Permet de découpler les dépendances entre objets.
Les dépendances ne sont plus exprimées de manière statique dans le code mais déterminées dynamiquement à l'exécution.
The DI delegates the creation of a service that an object consumes outside of this object.
- classes are loosely coupled
- classes follow the single responsibility principle
- it becomes easier to mock the dependencies so to create unit tests
- by relying on abstractions instead of implementations, code can easily vary a given implementation
Maintainability |
classes are loosely coupled and follow the single responsibility principle
|
Testability |
easier to mock the dependencies so to create unit tests
|
Readability |
single responsibility principle
|
Flexibility |
easier to switch from an implementation to another
|
Registration lifetimes
Registration lifetime
|
Description
|
Transient |
create a new instance anytime that their injection into a class is required
|
Scoped |
equivalent to the lifetime of the HTTP request
|
Singleton |
from the moment the application starts until it shuts down
|
Exemple
Le MainViewModel veut utiliser le DataService mais ne veut pas:
- de lien statique avec la classe DataService
- prendre en charge sa construction
Dépendance entre MainViewModel et DataService
- lien statique avec la classe DataService
- prend en charge la construction de DataService
|
class MainViewModel
{
private DataService _dataService;
public MainViewModel()
{
_dataService = new DataService();
}
}
|
Création d'une interface
- plus de lien statique avec la classe DataService grâce à l'interface IDataService
- prend en charge la construction de DataService
|
interface IDataService { }
class DataService : IDataService { }
class MainViewModel
{
private IDataService _dataService;
public MainViewModel()
{
_dataService = new DataService();
}
}
|
Injection du service
- plus de lien statique avec la classe DataService grâce à l'interface IDataService
- un objet DataService est injecté dans le constructeur de MainViewModel
|
class MainViewModel
{
private IDataService _dataService;
// la création du service se fait en dehors de la classe qui l'utilise
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
}
}
|
Reduce the number of parameter in the ctor by injecting a dependency object
MyViewModel.cs
|
public MyViewModel(IMyViewModelDependencies dependencies)
{
this.dependencies = dependencies;
this.myService = dependencies.MyService;
}
|
IMyViewModelDependencies.cs
|
internal interface IMyViewModelDependencies
{
IMyService MyService { get; }
}
|
MyViewModelDependencies.cs
|
internal sealed class MyViewModelDependencies : IMyViewModelDependencies
{
public MyViewModelDependencies(IServiceLocator serviceLocator)
{
this.MyService = serviceLocator.GetInstance<IMyService>();
}
public IMyService MyService { get; }
}
|
ServiceCollectionExtensions.cs
|
internal static class ServiceCollectionExtensions
{
public static void AddViewModelDependencies(this IServiceCollection @this)
{
@this.AddTransient<IMyService, MyService>();
}
}
|
|
this.services.AddViewModelDependencies();
|
Allow to inject multiple instance of the same type differentiated by a key.
Program.cs
|
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
|
MyService.cs
|
public MyService([FromKeyedServices("big")] ICache bigCache)
{ }
|
IoC frameworks