Principes de l’Injection de Dépendances en C#
Apprenez les principes de l’Injection de Dépendances en C#, la gestion des dépendances et le couplage faible avec exemples.
En développement logiciel, l’Injection de Dépendances (DI) est un modèle de conception important utilisé pour gérer les dépendances. Avec la DI, les classes reçoivent les objets dont elles ont besoin depuis l’extérieur au lieu de les créer en interne. Cela rend le code plus flexible, testable et maintenable. Dans l’écosystème C# et .NET Core, la DI est prise en charge nativement.
Qu’est-ce qu’une dépendance ?
Une classe dépend d’une autre lorsqu’elle a besoin de sa fonctionnalité.
Par exemple, un OrderService peut nécessiter une instance de ILogger lors de la création d’une commande.
Si OrderService utilise directement new Logger(), il devient fortement couplé à la classe Logger.
public class OrderService
{
private readonly Logger _logger = new Logger();
public void CreateOrder(string product)
{
_logger.Log($"Commande créée : {product}");
}
}
public class Logger
{
public void Log(string message) => Console.WriteLine(message);
}
Avec cette approche, le Logger ne peut pas être remplacé.
Si vous souhaitez utiliser un autre système de journalisation, vous devez modifier le code de OrderService.
C’est précisément là que l’Injection de Dépendances intervient.
Solution avec l’Injection de Dépendances
Avec la DI, les dépendances sont abstraites et fournies de l’extérieur (par le constructeur ou les paramètres de méthode).
Ainsi, OrderService dépend de l’interface ILogger, et le monde extérieur décide quel logger utiliser.
public interface ILogger
{
void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message) => Console.WriteLine("[Console] " + message);
}
public class FileLogger : ILogger
{
public void Log(string message) =>
System.IO.File.AppendAllText("log.txt", message + "\n");
}
public class OrderService
{
private readonly ILogger _logger;
// Injection par constructeur
public OrderService(ILogger logger)
{
_logger = logger;
}
public void CreateOrder(string product)
{
_logger.Log($"Commande créée : {product}");
}
}
class Program
{
static void Main()
{
// Différents loggers peuvent être choisis
ILogger logger = new ConsoleLogger();
var service = new OrderService(logger);
service.CreateOrder("Ordinateur portable");
}
}
Dans cet exemple, OrderService n’est plus lié à une classe Logger spécifique ;
il ne dépend que de l’interface ILogger.
Ainsi, ConsoleLogger ou FileLogger peuvent être utilisés facilement.
Types d’Injection de Dépendances
- Injection par constructeur : Les dépendances sont fournies via le constructeur (la méthode la plus courante).
- Injection par propriété : Les dépendances sont affectées via des propriétés publiques.
- Injection par méthode : Les dépendances sont passées via les paramètres de méthode.
Utilisation de la DI dans .NET Core
Dans les applications .NET Core, un conteneur DI intégré est disponible.
Les services sont enregistrés dans Program.cs ou Startup.cs, et sont injectés automatiquement dans les classes qui en ont besoin.
var builder = WebApplication.CreateBuilder(args);
// Enregistrer les services
builder.Services.AddScoped<ILogger, ConsoleLogger>();
builder.Services.AddScoped<OrderService>();
var app = builder.Build();
app.MapGet("/order", (OrderService service) =>
{
service.CreateOrder("Téléphone");
return "Commande traitée.";
});
app.Run();
Ici, le conteneur DI crée automatiquement une instance de ConsoleLogger pour OrderService et l’injecte.
Avantages
- Faible couplage : Les classes dépendent des interfaces plutôt que des implémentations concrètes.
- Testabilité : Les tests unitaires sont facilités grâce aux mocks ou objets factices.
- Flexibilité : Les différentes implémentations peuvent être remplacées facilement.
- Maintenabilité : Les dépendances sont gérées de manière centralisée, ce qui améliore la lisibilité du code.
TL;DR
- Injection de Dépendances : Les classes reçoivent les objets dont elles ont besoin depuis l’extérieur.
- Injection par constructeur : La méthode la plus courante ; les dépendances sont fournies via le constructeur.
- .NET Core : Fournit un conteneur DI intégré.
- Avantages : Offre une architecture plus flexible, testable et facile à maintenir.
Articles connexes
Classes, Objets, Propriétés et Méthodes en C#
Découvrez comment les classes, objets, propriétés et méthodes en C# constituent les fondements de la programmation orientée objet.
Encapsulation, Héritage et Polymorphisme en C#
Apprenez l’encapsulation, l’héritage et le polymorphisme en C# avec des exemples pour maîtriser les bases de la POO.
Espaces de noms et assemblies en C#
Apprenez les concepts de namespaces et d’assemblies en C# pour structurer le code et gérer efficacement les dépendances.
Interfaces et Classes Abstraites en C#
Découvrez les interfaces et classes abstraites en C#, leurs différences et quand les utiliser pour concevoir un code maintenable.
Méthodes et utilisation des paramètres en C#
Apprenez à définir des méthodes et à utiliser des paramètres en C#, y compris les paramètres par valeur et par référence avec exemples.
Principes SOLID en C#
Application des principes SOLID en C# avec des exemples : pour un code flexible, maintenable et testable.