Factory- und Options-Patterns
Verwenden Sie Factory-Delegates, IServiceProvider und das Options-Pattern für bedingte oder konfigurierbare Abhängigkeiten.
Factory- und Options-Patterns ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 4 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.
Wenn Konstruktorinjektion nicht ausreicht
Manchmal müssen Sie Dienste bedingt auf Grundlage von Laufzeitdaten erstellen oder sie je nach Anwendungsfall unterschiedlich konfigurieren. Hier kommen Factory-Pattern und Options-Pattern zum Einsatz.
Factory-Delegaten mit AddTransient
Sie können AddTransient, AddScoped oder AddSingleton einen Factory-Delegaten übergeben. Der Delegat erhält IServiceProvider, sodass Sie andere Dienste auflösen können.
builder.Services.AddTransient<IPaymentGateway>(sp =>
{
var config = sp.GetRequiredService<IOptions<PaymentConfig>>().Value;
return config.Provider == "stripe"
? new StripeGateway(config.ApiKey)
: new PayPalGateway(config.ClientId, config.Secret);
});Benannte Optionen mit IOptionsSnapshot
Das Options-Pattern bindet Konfigurationsabschnitte an stark typisierte Klassen. Verwenden Sie IOptions<T> für Singletons und IOptionsSnapshot<T> für Werte, die pro Anfrage aktualisiert werden.
public class SmtpSettings
{
public string Host { get; set; } = "";
public int Port { get; set; } = 587;
public string Username { get; set; } = "";
}
// Registration
builder.Services.Configure<SmtpSettings>(
builder.Configuration.GetSection("Smtp"));
// Consumption
public class EmailService
{
private readonly SmtpSettings _settings;
public EmailService(IOptions<SmtpSettings> opts)
=> _settings = opts.Value;
}IOptionsMonitor für Hot Reload
IOptionsMonitor<T> stellt beim Zugriff den aktuellen Optionswert bereit und benachrichtigt Sie über Änderungen an der Konfiguration – ideal für Singletons, die laufende Konfigurationsaktualisierungen benötigen.
public class FeatureFlagService
{
private readonly IOptionsMonitor<FeatureFlags> _monitor;
public FeatureFlagService(IOptionsMonitor<FeatureFlags> monitor)
=> _monitor = monitor;
public bool IsEnabled(string flag)
{
// Always reads the latest config value
return _monitor.CurrentValue.Flags.GetValueOrDefault(flag);
}
}Benannte Optionen
Mit benannten Optionen können Sie mehrere Konfigurationen desselben Typs registrieren. Verwenden Sie Configure<T>(name, ...) und lösen Sie sie mit IOptionsSnapshot<T>.Get(name) auf.
builder.Services.Configure<S3Settings>("primary",
builder.Configuration.GetSection("S3:Primary"));
builder.Services.Configure<S3Settings>("backup",
builder.Configuration.GetSection("S3:Backup"));
public class S3Service
{
public S3Service(IOptionsSnapshot<S3Settings> opts)
{
var primary = opts.Get("primary");
var backup = opts.Get("backup");
}
}Optionen beim Start validieren
Verwenden Sie ValidateDataAnnotations() oder einen benutzerdefinierten Validator, um sicherzustellen, dass die Konfiguration vor dem Start der Anwendung korrekt ist. Kombinieren Sie dies mit ValidateOnStart(), damit Fehler sofort zum Abbruch führen.
public class SmtpSettings
{
[Required] public string Host { get; set; } = "";
[Range(1, 65535)] public int Port { get; set; } = 587;
}
builder.Services
.AddOptions<SmtpSettings>()
.Bind(builder.Configuration.GetSection("Smtp"))
.ValidateDataAnnotations()
.ValidateOnStart();Abstraktes Factory-Pattern
Mit einer abstrakten Factory-Schnittstelle können Sie eine Factory in Dienste injizieren und die Erstellung verzögern, bis Laufzeitdaten verfügbar sind – ohne eine direkte Abhängigkeit von IServiceProvider einzugehen.
public interface IReportFactory
{
IReport Create(string reportType);
}
public class ReportFactory : IReportFactory
{
private readonly IServiceProvider _sp;
public ReportFactory(IServiceProvider sp) => _sp = sp;
public IReport Create(string reportType) => reportType switch
{
"pdf" => _sp.GetRequiredService<PdfReport>(),
"excel"=> _sp.GetRequiredService<ExcelReport>(),
_ => throw new ArgumentException("Unknown type")
};
}
builder.Services.AddTransient<IReportFactory, ReportFactory>();Keyed Services (.NET 8)
.NET 8 führt Keyed Services ein: Registrieren Sie mehrere Implementierungen unter verschiedenen Schlüsseln und lösen Sie die richtige mit [FromKeyedServices] oder GetKeyedService auf.
builder.Services.AddKeyedScoped<IPaymentGateway, StripeGateway>("stripe");
builder.Services.AddKeyedScoped<IPaymentGateway, PayPalGateway>("paypal");
// Resolve in a class:
public class CheckoutService(
[FromKeyedServices("stripe")] IPaymentGateway stripe,
[FromKeyedServices("paypal")] IPaymentGateway paypal) { }PostConfigure für Überschreibungen
PostConfigure wird nach allen Configure-Aufrufen ausgeführt. Verwenden Sie es, um Überschreibungen in Tests anzuwenden oder Invarianten unabhängig von der geladenen Konfiguration durchzusetzen.
// In integration tests: force test values after real config
builder.Services.PostConfigure<SmtpSettings>(opts =>
{
opts.Host = "smtp.test.local";
opts.Port = 25;
});Erweiterungsmethoden für IServiceCollection
Kapseln Sie Ihre Registrierungen in Erweiterungsmethoden, damit Program.cs übersichtlich bleibt und die Module projektübergreifend wiederverwendet werden können.
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddPaymentServices(
this IServiceCollection services,
IConfiguration config)
{
services.Configure<PaymentConfig>(config.GetSection("Payment"));
services.AddScoped<IPaymentGateway, StripeGateway>();
services.AddScoped<PaymentService>();
return services;
}
}
// Usage in Program.cs:
builder.Services.AddPaymentServices(builder.Configuration);Praxisbeispiel: Benachrichtigungen mit mehreren Anbietern
Wenn Sie eine Factory und benannte Optionen gemeinsam verwenden, können Sie den passenden Benachrichtigungsanbieter zur Laufzeit anhand der in der Datenbank gespeicherten Benutzerpräferenz auswählen.
builder.Services.AddKeyedScoped<INotifier, EmailNotifier>("email");
builder.Services.AddKeyedScoped<INotifier, SmsNotifier>("sms");
builder.Services.AddKeyedScoped<INotifier, PushNotifier>("push");
public class NotificationService
{
private readonly IServiceProvider _sp;
public NotificationService(IServiceProvider sp) => _sp = sp;
public Task SendAsync(string channel, string message)
{
var notifier = _sp.GetRequiredKeyedService<INotifier>(channel);
return notifier.SendAsync(message);
}
}Kurzprüfung
Welche Schnittstelle stellt den aktuellen Optionswert bereit UND benachrichtigt über Konfigurationsänderungen und eignet sich dadurch für Singleton-Dienste?
Zusammenfassung: Factory- und Options-Pattern
Wichtige Erkenntnisse:
- Factory-Delegaten in
Add*-Methoden ermöglichen die bedingte oder zur Laufzeit konfigurierte Erstellung von Diensten - Das Options-Pattern bindet Konfigurationsabschnitte an stark typisierte POCOs
IOptions= statisch,IOptionsSnapshot= pro Anfrage,IOptionsMonitor= laufende Aktualisierungen- Validieren Sie Optionen beim Start mit
ValidateDataAnnotations().ValidateOnStart() - Keyed Services (.NET 8) ersetzen Factory-Umgehungslösungen für benannte Implementierungen
Häufig gestellte Fragen
Ist die Lektion „Factory- und Options-Patterns“ kostenlos?
Ja — der vollständige Text von „Factory- und Options-Patterns“ 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 „Factory- und Options-Patterns“?
Verwenden Sie Factory-Delegates, IServiceProvider und das Options-Pattern für bedingte oder konfigurierbare Abhängigkeiten. 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 4 von 4.
Wie lange dauert die Lektion „Factory- und Options-Patterns“?
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
- Grundlagen von DI-Containern
- Lebensdauern von Diensten: Transient, Scoped, Singleton
- Konstruktor-Injection und Schnittstellen
- Factory- und Options-Patterns