3

依存関係といくつかの文字列値の両方を初期化する必要があるクラスを持つという問題によく直面します。たとえば、次のコードを考えてみましょう。

public class CustomerService
{
   public CustomerService(ITcpConnection connection, string realm)
   {
   }
}

問題は、文字列パラメーターが追加されているため、DI コンテナーからそれを簡単に取得できないことです。この問題を解決する最善の方法は何ですか? これらは私が考えることができる方法です:

  1. Initialize メソッド (Mark Seeman の定義による一時的な結合を提供するため、十分ではありません。あまり良い方法ではないことに同意します)
  2. 抽象ファクトリ (パラメーターは構成であり、構成を行うときにそれを知っているため、間接的なレイヤーを 1 つ追加する必要はありません)
  3. 例のように使用し、クラスのインスタンスをDIコンテナに登録します
4

1 に答える 1

3

プリミティブ構成値と (サービス) 依存関係を同じコンストラクターに混在させることは避けるのが最善です。それらは DI 構成を複雑にし、多くの場合、判読不能で脆弱な構成ルートにつながります。

代わりに次の操作を行います。

オプション 1: その構成値を抽象化する

同じ構成値が複数のクラスに注入されると、多くの場合、抽象化が失われます。この良い例は、string connectionStringすべてのリポジトリへの値の注入です。この場合、アプリケーションにはIConnectionFactory抽象化 (または類似のもの) が欠けている可能性があります。接続文字列を多くのクラスに注入する代わりに、接続文字列を実装に注入し(おそらく、その接続文字列のみをコンストラクター引数として取ります)、他のサービスがの代わりにIConnectionFactory依存できるようにする必要があります。このように、これらのサービスは接続の作成を処理する必要がありません。接続ファクトリーはこれを行うことができます。IConnectionFactorystring

オプション 2: 構成値を構成タイプにラップする

プリミティブ型は、型の解決に関してあいまいさを引き起こします。注入されたのは、ファイル パスですか、それとも接続文字列ですかstring? あなたintが注入しているのは、再試行の回数ですか、それとも顧客が商品を購入できる最低年齢ですか?

あいまいさを避けるために、クラスが 1 つの値しか必要としない場合でも、クラスのすべての構成値を独自の構成タイプにラップすることをお勧めします。SqlUnitOfWorkSettingsをラップするthis を例にとりますTimeSpan

public sealed class SqlUnitOfWorkSettings
{
    public readonly TimeSpan ConnectionTimeout;

    public SqlUnitOfWorkSettings(TimeSpan connectionTimeout)
    {
        this.ConnectionTimeout = connectionTimeout;
    }
}

TimeSpanに依存する代わりに、 は代わりにSqlUnitOfWork依存できるようになりましSqlUnitOfWorkSettingsた。

public sealed class SqlUnitOfWork : IUnitOfWork
{
    private readonly SqlUnitOfWorkSettings settings;

    public SqlUnitOfWork(SqlUnitOfWorkSettings settings)
    {
        this.settings = settings;
    }
}

新しい構成クラスを使用すると、あいまいさがなくなるため、DI コンテナーへの登録が簡素化されます。

container.RegisterInstance(
    new SqlUnitOfWorkSettings(connectionTimeout: TimeSpan.FromSeconds(30));
container.Register<IUnitOfWork, SqlUnitOfWork>(Lifestyle.Scoped);

オプション 3: サブタイプを作成する

構成クラスの使用がオプションではない場合 (たとえば、ソース コードを変更できないため)、コンポジション ルートに配置されたサブタイプを派生させ、適切なコンストラクターを定義し、代わりにそのサブタイプを登録できます。

public class MyService : SomeExternalService
{
    public MyService(ISomeDependency dep) : base(dep, "My Config Value") { }
}

// Registration
container.Register<IService, MyService>();
于 2013-05-27T12:17:36.313 に答える