Wird geladen...

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


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


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