Menu
Coddy logo textTech

Dependency Injection Grundlagen

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 46 von 70.

Dependency Injection (DI) ist eine Technik, bei der eine Klasse ihre Abhängigkeiten von außen erhält, anstatt sie selbst zu erstellen. Dies macht den Code flexibler, testbarer und lose gekoppelt.

Ohne DI erstellt eine Klasse ihre eigenen Abhängigkeiten, was Änderungen oder Tests erschwert:

public class OrderService
{
    private EmailSender sender = new EmailSender();  // Eng gekoppelt
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Mit DI werden Abhängigkeiten über den Konstruktor übergeben:

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Jetzt weiß OrderService nicht mehr und es ist ihm egal, ob E-Mail, SMS oder ein Mock-Sender für Tests verwendet wird. Die Abhängigkeit wird beim Erstellen des Objekts „injiziert“:

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // Email: Bestellung aufgegeben

Dieses Muster folgt dem Prinzip, von Abstraktionen (Schnittstellen) statt von konkreten Implementierungen abhängig zu sein. Es ermöglicht den Austausch von Implementierungen, ohne die Klasse zu ändern, die sie verwendet, was für Unit-Tests und die Aufrechterhaltung flexibler Architekturen unerlässlich ist.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Logging-System bauen, das die Leistungsfähigkeit von Dependency Injection demonstriert. Anstatt fest zu verdrahten, wie Protokolle geschrieben werden, erstellen Sie eine flexible Logger-Klasse, die mit jedem Protokollziel arbeiten kann – Konsole, Dateisimulation oder etwas anderem – ohne die Details zu kennen.

Sie werden Ihren Code über drei Dateien organisieren:

  • ILogWriter.cs: Definieren Sie ein Interface namens ILogWriter im Namespace Logging. Dieses Interface repräsentiert den Vertrag für jedes Protokollziel und sollte eine einzige Methode Write(string message) haben, die einen String zurückgibt, der beschreibt, wohin die Nachricht geschrieben wurde.
  • LogWriters.cs: Erstellen Sie zwei konkrete Implementierungen von ILogWriter im Namespace Logging:
    • ConsoleLogWriter – seine Write-Methode gibt Console: {message} zurück
    • FileLogWriter – nimmt einen Dateinamen über seinen Konstruktor entgegen und seine Write-Methode gibt File[{filename}]: {message} zurück
  • Logger.cs: Erstellen Sie eine Logger-Klasse im Namespace Logging, die ihre Abhängigkeit über Constructor Injection erhält. Der Logger sollte:
    • Einen ILogWriter über seinen Konstruktor akzeptieren und in einem privaten Feld speichern
    • Eine Log(string message)-Methode haben, die an den injizierten Writer delegiert und das Ergebnis zurückgibt
  • Program.cs: Demonstrieren Sie Dependency Injection, indem Sie zwei verschiedene Logger erstellen – einen mit einem ConsoleLogWriter und einen mit einem FileLogWriter. Zeigen Sie, wie sich dieselbe Logger-Klasse unterschiedlich verhält, je nachdem, welche Abhängigkeit injiziert wird.

Sie erhalten zwei Eingaben:

  • Den Dateinamen für den Datei-Logger
  • Die zu protokollierende Nachricht

Erstellen Sie einen Logger mit einem ConsoleLogWriter und protokollieren Sie die Nachricht. Erstellen Sie dann einen weiteren Logger mit einem FileLogWriter (unter Verwendung des Dateinamens aus der Eingabe) und protokollieren Sie dieselbe Nachricht. Geben Sie jedes Ergebnis in einer eigenen Zeile aus.

Wenn die Eingaben beispielsweise app.log und System started sind, sollte die Ausgabe wie folgt aussehen:

Console: System started
File[app.log]: System started

Beachten Sie, dass sich die Logger-Klasse nie ändert – sie funktioniert mit jeder ILogWriter-Implementierung. Dies ist der Kern von Dependency Injection: Der Logger hängt von einer Abstraktion (dem Interface) ab, und die konkrete Implementierung wird von außen "injiziert". Sie könnten später problemlos einen DatabaseLogWriter oder CloudLogWriter hinzufügen, ohne die Logger-Klasse überhaupt zu ändern!

Spickzettel

Dependency Injection (DI) ist eine Technik, bei der eine Klasse ihre Abhängigkeiten von außen erhält, anstatt sie selbst zu erstellen, wodurch der Code flexibler, testbarer und lose gekoppelt wird.

Ohne DI (eng gekoppelt):

public class OrderService
{
    private EmailSender sender = new EmailSender();  // Eng gekoppelt
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Mit DI (lose gekoppelt):

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Injizieren der Abhängigkeit:

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // Email: Order placed

DI folgt dem Prinzip, von Abstraktionen (Schnittstellen) statt von konkreten Implementierungen abzuhängen, was den Austausch von Implementierungen ermöglicht, ohne die Klasse, die sie verwendet, zu ändern.

Probier es selbst

using System;
using Logging;

class Program
{
    public static void Main(string[] args)
    {
        // Eingaben lesen
        string filename = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Erstelle einen Logger mit einem ConsoleLogWriter und protokolliere die Nachricht
        // Das Ergebnis ausgeben

        // TODO: Erstelle einen weiteren Logger mit einem FileLogWriter (unter Verwendung von filename) und protokolliere dieselbe Nachricht
        // Das Ergebnis ausgeben
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung