0Pricing
C# Academy · レッスン

FactoryとOptionsパターン

ファクトリデリゲート、IServiceProvider、Optionsパターンを使って、条件付きまたは設定可能な依存関係を扱います。

「FactoryとOptionsパターン」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

コンストラクターインジェクションだけでは不十分な場合

実行時のデータに基づいて条件付きでサービスを作成したり、ユースケースごとに異なる設定を適用したりする必要がある場合があります。そのようなときにファクトリーパターンとOptionsパターンが力を発揮します。

AddTransientを使用したファクトリーデリゲート

AddTransient、AddScoped、AddSingletonにファクトリーデリゲートを渡せます。デリゲートにはIServiceProviderが渡されるため、他のサービスを解決できます。

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

IOptionsSnapshotを使用した名前付きオプション

Optionsパターンは、設定セクションを強く型付けされたクラスにバインドします。SingletonにはIOptions<T>を、リクエストごとに更新される値にはIOptionsSnapshot<T>を使用します。

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

IOptionsMonitor<T>はアクセス時点の現在のオプション値を提供し、設定が変更されたときに通知します。ライブな設定更新が必要なSingletonに最適です。

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

名前付きオプション

名前付きオプションを使用すると、同じ型に対して複数の設定を登録できます。Configure<T>(name, ...)を使用して登録し、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");
    }
}

起動時のオプション検証

ValidateDataAnnotations()またはカスタムバリデーターを使用して、アプリの起動前に設定が正しいことを確認します。ValidateOnStart()と組み合わせると、問題を即座に検出して終了する動作にできます。

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

Abstract Factoryパターン

Abstract Factoryインターフェイスを使用すると、サービスにファクトリーを注入し、実行時のデータが利用可能になるまで構築を遅延できます。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>();

キー付きサービス(.NET 8)

.NET 8ではキー付きサービスが導入されました。異なるキーで複数の実装を登録し、[FromKeyedServices]または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

PostConfigureは、すべてのConfigure呼び出しの後に実行されます。テストでオーバーライドを適用したり、読み込まれた設定の内容にかかわらず不変条件を適用したりするために使用します。

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

IServiceCollectionの拡張メソッド

登録処理を拡張メソッドにまとめると、Program.csをすっきり保ち、プロジェクト間でモジュールを再利用できます。

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

実践例: 複数プロバイダーによる通知

ファクトリーと名前付きオプションを組み合わせると、データベースに保存されたユーザーの設定に基づいて、実行時に適切な通知プロバイダーを選択できます。

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

クイックチェック

現在のオプション値を提供し、設定変更時に通知も行うため、Singletonサービスに適しているインターフェイスはどれですか。

まとめ: ファクトリーとOptionsパターン

重要なポイント:

  • Add*メソッドのファクトリーデリゲートにより、条件付きまたは実行時に設定されたサービスの作成が可能になります
  • Optionsパターンは、設定セクションを強く型付けされたPOCOにバインドします
  • IOptions = 静的、IOptionsSnapshot = リクエストごと、IOptionsMonitor = ライブ更新
  • ValidateDataAnnotations().ValidateOnStart()を使用して、起動時にオプションを検証します
  • キー付きサービス(.NET 8)により、名前付き実装のためのファクトリーによる回避策が不要になります

よくある質問

「FactoryとOptionsパターン」レッスンは無料ですか?

はい。「FactoryとOptionsパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「FactoryとOptionsパターン」で何を学びますか?

ファクトリデリゲート、IServiceProvider、Optionsパターンを使って、条件付きまたは設定可能な依存関係を扱います。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「FactoryとOptionsパターン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. DIコンテナーの基礎
  2. サービスのライフタイム:Transient、Scoped、Singleton
  3. コンストラクターインジェクションとインターフェース
  4. FactoryとOptionsパターン
← C# Academyに戻る