0Pricing
C# Academy · Lezione

Pattern Factory e Options

Usi factory delegate, IServiceProvider e il pattern Options per gestire dipendenze condizionali o configurabili.

Pattern Factory e Options è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.

Quando l'iniezione tramite costruttore non basta

A volte è necessario creare servizi in modo condizionale, in base a dati disponibili durante l'esecuzione, oppure configurarli in modo diverso per ogni caso d'uso. È in questi casi che i pattern Factory e Options sono particolarmente utili.

Factory delegate con AddTransient

Può passare una factory delegate a AddTransient, AddScoped o AddSingleton. La delegate riceve IServiceProvider, consentendo di risolvere altri servizi.

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

Options denominate con IOptionsSnapshot

Il pattern Options associa le sezioni di configurazione a classi fortemente tipizzate. Utilizzi IOptions<T> per i Singleton e IOptionsSnapshot<T> per i valori aggiornati a ogni richiesta.

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 per l'hot reload

IOptionsMonitor<T> fornisce il valore corrente dell'opzione al momento dell'accesso e invia una notifica quando la configurazione cambia: è perfetto per i Singleton che devono ricevere aggiornamenti della configurazione in tempo reale.

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

Options denominate

Le options denominate consentono di registrare più configurazioni dello stesso tipo. Utilizzi Configure<T>(name, ...) e risolva il valore con 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");
    }
}

Convalida delle Options all'avvio

Utilizzi ValidateDataAnnotations() o un validator personalizzato per verificare che la configurazione sia corretta prima dell'avvio dell'applicazione. Lo combini con ValidateOnStart() per ottenere un comportamento fail-fast.

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

Pattern Abstract Factory

Un'interfaccia Abstract Factory consente di inserire una factory nei servizi, rimandando la costruzione fino a quando non sono disponibili i dati di runtime, senza creare una dipendenza diretta da 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>();

Servizi keyed (.NET 8)

.NET 8 introduce i servizi keyed: registri più implementazioni con chiavi diverse e risolva quella corretta con [FromKeyedServices] o 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 per le sostituzioni

PostConfigure viene eseguito dopo tutte le chiamate a Configure. Lo utilizzi per applicare sostituzioni nei test o per imporre invarianti indipendentemente dalla configurazione caricata.

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

Metodi di estensione di IServiceCollection

Raccolga le registrazioni in metodi di estensione per mantenere pulito Program.cs e rendere i moduli riutilizzabili in più progetti.

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

Caso reale: notifiche con più provider

Utilizzando insieme una factory e le options denominate, può selezionare a runtime il provider di notifiche corretto in base alla preferenza dell'utente memorizzata nel database.

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

Verifica rapida

Quale interfaccia fornisce il valore corrente delle options E invia notifiche quando la configurazione cambia, risultando quindi adatta ai servizi Singleton?

Riepilogo: pattern Factory e Options

Punti chiave:

  • Le factory delegate nei metodi Add* consentono di creare servizi in modo condizionale o configurato a runtime
  • Il pattern Options associa le sezioni di configurazione a POCO fortemente tipizzati
  • IOptions = statiche, IOptionsSnapshot = per richiesta, IOptionsMonitor = aggiornamenti in tempo reale
  • Convalidi le options all'avvio con ValidateDataAnnotations().ValidateOnStart()
  • I servizi keyed (.NET 8) sostituiscono le soluzioni basate su factory per le implementazioni denominate

Domande Frequenti

La lezione «Pattern Factory e Options» è gratuita?

Sì — il testo completo di «Pattern Factory e Options» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.

Cosa imparerò in «Pattern Factory e Options»?

Usi factory delegate, IServiceProvider e il pattern Options per gestire dipendenze condizionali o configurabili. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Pattern Factory e Options»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Fondamenti dei container DI
  2. Durata dei servizi: Transient, Scoped, Singleton
  3. Iniezione tramite costruttore e interfacce
  4. Pattern Factory e Options
← Torna a C# Academy