0Pricing
C# Academy · Lektion

Konstruktor-Injection und Schnittstellen

Wenden Sie Konstruktor-Injection mit schnittstellenbasierter Gestaltung an, um Komponenten zu entkoppeln und Unit-Tests zu ermöglichen.

Konstruktor-Injection und Schnittstellen ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Grundlagen der Konstruktorinjektion

Konstruktorinjektion ist das häufigste DI-Muster. Eine Klasse deklariert ihre Abhängigkeiten als Konstruktorparameter, und der Container stellt sie bei der Instanziierung bereit.

Dadurch sind Abhängigkeiten explizit, erforderlich und sichtbar.

Die Schnittstelle definieren

Beginnen Sie mit einer Schnittstelle, die den Vertrag definiert. Dadurch können verschiedene Implementierungen – etwa eine echte, eine simulierte oder eine speicherinterne – ausgetauscht werden, ohne den abhängigen Code zu ändern.

public interface IProductRepository
{
    Task<Product?> GetByIdAsync(int id);
    Task<IEnumerable<Product>> GetAllAsync();
    Task AddAsync(Product product);
}

Die Schnittstelle implementieren

Die konkrete Implementierung übernimmt die eigentliche Arbeit – Datenbankaufrufe, HTTP-Anfragen usw. Der aufrufende Code muss nie wissen, welche Implementierung er erhält.

public class SqlProductRepository : IProductRepository
{
    private readonly AppDbContext _db;

    public SqlProductRepository(AppDbContext db) => _db = db;

    public async Task<Product?> GetByIdAsync(int id)
        => await _db.Products.FindAsync(id);

    public async Task<IEnumerable<Product>> GetAllAsync()
        => await _db.Products.ToListAsync();

    public async Task AddAsync(Product product)
    {
        _db.Products.Add(product);
        await _db.SaveChangesAsync();
    }
}

Über den Konstruktor verwenden

Die Serviceschicht übernimmt IProductRepository als Konstruktorparameter. Sie kennt SqlProductRepository nicht, sondern nur den Schnittstellenvertrag.

public class ProductService
{
    private readonly IProductRepository _repo;
    private readonly ILogger<ProductService> _logger;

    public ProductService(
        IProductRepository repo,
        ILogger<ProductService> logger)
    {
        _repo = repo;
        _logger = logger;
    }

    public async Task<Product?> GetProductAsync(int id)
    {
        _logger.LogInformation("Fetching product {Id}", id);
        return await _repo.GetByIdAsync(id);
    }
}

Die Kette registrieren

Registrieren Sie jeden Dienst in der Kette. Der Container löst den vollständigen Abhängigkeitsgraphen automatisch auf: ProductService → IProductRepository → AppDbContext.

builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlite("Data Source=app.db"));

builder.Services.AddScoped<IProductRepository, SqlProductRepository>();
builder.Services.AddScoped<ProductService>();

Mit einem Mock testen

Da Abhängigkeiten über Schnittstellen injiziert werden, können Komponententests einen Mock oder eine Fälschung übergeben, ohne auf die Datenbank zuzugreifen. Das ist einer der größten Vorteile von DI.

// Using NSubstitute or Moq in a unit test
var mockRepo = Substitute.For<IProductRepository>();
mockRepo.GetByIdAsync(1).Returns(new Product { Id = 1, Name = "Widget" });

var logger = Substitute.For<ILogger<ProductService>>();
var svc = new ProductService(mockRepo, logger);

var result = await svc.GetProductAsync(1);
Assert.Equal("Widget", result?.Name);

Mehrere Konstruktorparameter

Eine Klasse kann viele Konstruktorparameter haben. Der Container löst sie alle auf, solange jeder registriert ist. Halten Sie Konstruktoren fokussiert – zu viele Parameter sind ein Anzeichen dafür, dass die Klasse zu viele Verantwortlichkeiten hat.

public class OrderService
{
    public OrderService(
        IOrderRepository orders,
        IProductRepository products,
        IEmailSender email,
        ILogger<OrderService> logger)
    {
        // all injected by DI container
    }
}

Das Service-Locator-Anti-Pattern vermeiden

Injizieren Sie IServiceProvider NICHT und rufen Sie GetService nicht innerhalb von Geschäftsmethoden auf. Dadurch werden Abhängigkeiten verborgen und Tests erschwert. Bevorzugen Sie die Konstruktorinjektion für expliziten, testbaren Code.

// BAD
public void Process(IServiceProvider sp)
{
    var repo = sp.GetService<IProductRepository>(); // hidden dep!
}

// GOOD
public class Processor
{
    private readonly IProductRepository _repo;
    public Processor(IProductRepository repo) => _repo = repo;
}

Syntax primärer Konstruktoren (C# 12)

C# 12 führt primäre Konstruktoren für alle Klassentypen ein. Dadurch können Sie Parameter direkt in der Klassendeklaration angeben und prägnanten DI-Code schreiben.

// C# 12 primary constructor
public class ProductService(
    IProductRepository repo,
    ILogger<ProductService> logger)
{
    public async Task<Product?> GetAsync(int id)
    {
        logger.LogInformation("Getting {Id}", id);
        return await repo.GetByIdAsync(id);
    }
}

Implementierungen austauschen

Ein wesentlicher Vorteil schnittstellenbasierter DI: Sie können eine Implementierung in einer einzigen Zeile austauschen, ohne aufrufenden Code zu ändern. Das ist nützlich, wenn Sie Datenbanken, Anbieter für den E-Mail-Versand oder Feature-Flags wechseln.

// Switch from SQL to in-memory for integration tests
if (environment.IsEnvironment("Test"))
    builder.Services.AddScoped<IProductRepository, InMemoryProductRepository>();
else
    builder.Services.AddScoped<IProductRepository, SqlProductRepository>();

Praxisbeispiel: Controller mit DI

ASP.NET Core-Controller verwenden die Konstruktorinjektion nativ. Das Framework löst alle Parameter auf und übergibt sie.

[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
    private readonly ProductService _svc;

    public ProductsController(ProductService svc) => _svc = svc;

    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        var product = await _svc.GetProductAsync(id);
        return product is null ? NotFound() : Ok(product);
    }
}

Kurzprüfung

Was ist der wichtigste Vorteil der Programmierung gegen Schnittstellen bei der Verwendung von DI?

Zusammenfassung: Konstruktorinjektion und Schnittstellen

Wichtige Erkenntnisse:

  • Deklarieren Sie Abhängigkeiten als Konstruktorparameter – der Container stellt sie bereit
  • Definieren Sie Schnittstellen für Dienstverträge; injizieren Sie die Schnittstelle, nicht den konkreten Typ
  • Schnittstellen ermöglichen einfaches Mocking in Komponententests und den Austausch von Implementierungen
  • Primäre Konstruktoren in C# 12 reduzieren Boilerplate in DI-intensiven Klassen
  • Vermeiden Sie das Service-Locator-Anti-Pattern – halten Sie Abhängigkeiten explizit

Häufig gestellte Fragen

Ist die Lektion „Konstruktor-Injection und Schnittstellen“ kostenlos?

Ja — der vollständige Text von „Konstruktor-Injection und Schnittstellen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Konstruktor-Injection und Schnittstellen“?

Wenden Sie Konstruktor-Injection mit schnittstellenbasierter Gestaltung an, um Komponenten zu entkoppeln und Unit-Tests zu ermöglichen. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Konstruktor-Injection und Schnittstellen“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Grundlagen von DI-Containern
  2. Lebensdauern von Diensten: Transient, Scoped, Singleton
  3. Konstruktor-Injection und Schnittstellen
  4. Factory- und Options-Patterns
← Zurück zu C# Academy