C# Academy · Lektion

Factory- och Options-mönster

Använd factory-delegater, IServiceProvider och Options-mönstret för att hantera villkorliga eller konfigurerbara beroenden.

Lektion 4 av 413 steg

Factory- och Options-mönster är en gratis lektion i C# Academy på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för C# Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i C# Academy innehåller totalt 4 lektioner.

När konstruktorinjektion inte räcker

Ibland behöver du skapa tjänster villkorligt, baserat på data vid körning, eller konfigurera dem olika för olika användningsfall. Då kommer fabriksmönster och Options-mönstret till sin rätt.

Fabriksdelegater med AddTransient

Du kan skicka en fabriksdelegat till AddTransient, AddScoped eller AddSingleton. Delegaten tar emot IServiceProvider, så att du kan hämta andra tjänster.

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);
});

Namngivna options med IOptionsSnapshot

Options-mönstret binder konfigurationssektioner till starkt typade klasser. Använd IOptions<T> för singleton-värden och IOptionsSnapshot<T> för värden som uppdateras per begäran.

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> tillhandahåller det aktuella optionsvärdet när det hämtas och meddelar dig när konfigurationen ändras – perfekt för Singleton-tjänster som behöver direkta konfigurationsuppdateringar.

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);
    }
}

Namngivna options

Med namngivna options kan du registrera flera konfigurationer av samma typ. Använd Configure<T>(name, ...) och hämta värdet med IOptionsSnapshot<T>.Get(name).

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");
    }
}

Validera options vid programstart

Använd ValidateDataAnnotations() eller en anpassad validator för att säkerställa att konfigurationen är korrekt innan programmet startar. Kombinera med ValidateOnStart() för att upptäcka fel direkt.

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();

Abstrakt fabriksmönster

Med ett abstrakt fabriksgränssnitt kan du injicera en fabrik i tjänster och skjuta upp skapandet tills data från körningen är tillgängliga – utan ett direkt beroende på IServiceProvider.

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 introducerar keyed services: registrera flera implementationer med olika nycklar och hämta rätt implementation med [FromKeyedServices] eller GetKeyedService.

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 åsidosättningar

PostConfigure körs efter alla anrop till Configure. Använd det för att tillämpa åsidosättningar i tester eller framtvinga invarians oavsett vilken konfiguration som lästes in.

// In integration tests: force test values after real config
builder.Services.PostConfigure<SmtpSettings>(opts =>
{
    opts.Host = "smtp.test.local";
    opts.Port = 25;
});

Tilläggsmetoder för IServiceCollection

Samla registreringarna i tilläggsmetoder för att hålla Program.cs ren och göra moduler återanvändbara i flera projekt.

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);

I praktiken: notifiering med flera leverantörer

Genom att använda en fabrik och namngivna options tillsammans kan du välja rätt notifieringsleverantör vid körning, baserat på användarens inställning som lagras i databasen.

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);
    }
}

Snabb kontroll

Vilket gränssnitt tillhandahåller det aktuella optionsvärdet OCH meddelar om konfigurationsändringar, vilket gör det lämpligt för Singleton-tjänster?

Sammanfattning: Fabriks- och Options-mönster

Viktiga lärdomar:

  • Fabriksdelegater i Add*-metoder gör det möjligt att skapa tjänster villkorligt eller med konfiguration från körningen
  • Options-mönstret binder konfigurationssektioner till starkt typade POCO-klasser
  • IOptions = statiskt, IOptionsSnapshot = per begäran, IOptionsMonitor = direkta uppdateringar
  • Validera options vid programstart med ValidateDataAnnotations().ValidateOnStart()
  • Keyed services (.NET 8) ersätter fabrikslösningar för namngivna implementationer
Gratis att börja

Lär dig C# med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
93
Lektioner
346

Vanliga frågor

Är lektionen ”Factory- och Options-mönster” gratis?

Ja – hela texten till ”Factory- och Options-mönster” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i C# Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i C# Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Factory- och Options-mönster”?

Använd factory-delegater, IServiceProvider och Options-mönstret för att hantera villkorliga eller konfigurerbara beroenden. Ni övar på C# Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig C# Academy?

Du behöver inga förkunskaper. Utbildningen i C# Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Factory- och Options-mönster”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här C# Academy-lektionen?

Ja. Varje C# Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Grunderna i DI-containrar
  2. Tjänstelivslängder: Transient, Scoped, Singleton
  3. Konstruktorinjektion och gränssnitt
  4. Factory- och Options-mönster
← Tillbaka till C# Academy