Dependency Injection Grundlagen in C#
Lernen Sie die Grundlagen von Dependency Injection in C#, um Abhängigkeiten zu verwalten und lose Kopplung zu erreichen.
In der Softwareentwicklung ist Dependency Injection (DI) ein wichtiges Entwurfsmuster zur Verwaltung von Abhängigkeiten. Mit DI erhalten Klassen die Objekte, die sie benötigen, von außen, anstatt sie intern zu erzeugen. Dadurch wird der Code flexibler, testbarer und wartbarer. Im C#- und .NET-Core-Ökosystem wird DI standardmäßig unterstützt.
Was ist eine Abhängigkeit?
Eine Klasse ist von einer anderen abhängig, wenn sie deren Funktionalität benötigt.
Zum Beispiel könnte ein OrderService beim Erstellen einer Bestellung eine ILogger-Instanz benötigen.
Wenn OrderService direkt new Logger() verwendet, ist es stark an die Logger-Klasse gekoppelt.
public class OrderService
{
private readonly Logger _logger = new Logger();
public void CreateOrder(string product)
{
_logger.Log($"Bestellung erstellt: {product}");
}
}
public class Logger
{
public void Log(string message) => Console.WriteLine(message);
}
In diesem Ansatz kann der Logger nicht ersetzt werden.
Möchte man ein anderes Loggingsystem verwenden, muss der Code von OrderService geändert werden.
Genau hier kommt Dependency Injection ins Spiel.
Lösung mit Dependency Injection
Mit DI werden Abhängigkeiten abstrahiert und von außen bereitgestellt (über den Konstruktor oder Methodenparameter).
Auf diese Weise hängt OrderService vom ILogger-Interface ab, und die Außenwelt entscheidet, welcher Logger verwendet wird.
public interface ILogger
{
void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message) => Console.WriteLine("[Konsole] " + 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;
// Constructor Injection
public OrderService(ILogger logger)
{
_logger = logger;
}
public void CreateOrder(string product)
{
_logger.Log($"Bestellung erstellt: {product}");
}
}
class Program
{
static void Main()
{
// Unterschiedliche Logger können gewählt werden
ILogger logger = new ConsoleLogger();
var service = new OrderService(logger);
service.CreateOrder("Laptop");
}
}
In diesem Beispiel ist OrderService nicht mehr an eine bestimmte Logger-Klasse gebunden, sondern nur noch vom ILogger-Interface abhängig.
Dadurch können ConsoleLogger oder FileLogger problemlos ausgetauscht werden.
Arten der Dependency Injection
- Konstruktorinjektion: Abhängigkeiten werden über den Konstruktor bereitgestellt (am häufigsten verwendete Methode).
- Property Injection: Abhängigkeiten werden über öffentliche Properties zugewiesen.
- Method Injection: Abhängigkeiten werden über Methodenparameter übergeben.
DI in .NET Core verwenden
In .NET-Core-Anwendungen steht ein integrierter DI-Container zur Verfügung.
Dienste werden in Program.cs oder Startup.cs registriert und automatisch in die benötigten Klassen injiziert.
var builder = WebApplication.CreateBuilder(args);
// Dienste registrieren
builder.Services.AddScoped<ILogger, ConsoleLogger>();
builder.Services.AddScoped<OrderService>();
var app = builder.Build();
app.MapGet("/order", (OrderService service) =>
{
service.CreateOrder("Telefon");
return "Bestellung verarbeitet.";
});
app.Run();
Hier erstellt und injiziert der DI-Container automatisch eine ConsoleLogger-Instanz für OrderService.
Vorteile
- Lose Kopplung: Klassen hängen von Interfaces ab, nicht von konkreten Implementierungen.
- Testbarkeit: Unit-Tests sind mit Mocks oder Fake-Objekten einfacher.
- Flexibilität: Unterschiedliche Implementierungen können leicht ausgetauscht werden.
- Wartbarkeit: Abhängigkeiten werden zentral verwaltet, was die Lesbarkeit verbessert.
TL;DR
- Dependency Injection: Klassen erhalten die benötigten Objekte von außen.
- Konstruktorinjektion: Am häufigsten verwendet; Abhängigkeiten werden über den Konstruktor bereitgestellt.
- .NET Core: Bietet einen integrierten DI-Container.
- Vorteile: Sorgt für eine flexiblere, testbare und wartbare Architektur.
Ähnliche Artikel
Interfaces und Abstrakte Klassen in C#
Lernen Sie Interfaces und abstrakte Klassen in C#, ihre Unterschiede und den Einsatz für sauberes, erweiterbares Design.
Kapselung, Vererbung und Polymorphismus in C#
Lernen Sie Kapselung, Vererbung und Polymorphismus in C# mit Beispielen, um zentrale OOP-Konzepte sicher anzuwenden.
Klassen, Objekte, Eigenschaften und Methoden in C#
Erlernen Sie die Grundlagen von Klassen, Objekten, Eigenschaften und Methoden in C# für objektorientierte Programmierung.
Methoden und Parameterverwendung in C#
Lernen Sie Methoden und die Verwendung von Parametern in C#, einschließlich Wert- und Referenzparametern sowie optionalen Parametern.
Namespaces und Assemblies in C#
Erlernen Sie die Konzepte von Namespaces und Assemblies in C#, um Code zu strukturieren und Abhängigkeiten korrekt zu verwalten.
SOLID-Prinzipien mit C#
SOLID-Prinzipien mit C#-Beispielen: flexiblen, wartbaren und testbaren Code erstellen.