Simple Injector では、StructureMap に相当するもの(リフレクションを介しContainer.With("CustomerId").EqualTo(100).GetInstance<Customer>()
てプロパティを検索するもの) はありますか?CustomerId
1 に答える
Simple Injector にはこれに相当するものはありません。その理由は、そのような構成は通常、Service Locator アンチパターンにつながり、魔法の文字列の使用によって脆弱な構成につながるためです。
したがって、一般的な (コンテナに依存しない) アドバイスは、抽象ファクトリを使用することです (Mark Seemann がここで説明しているように)。アプリケーションは、コンテナーを使用する代わりに、抽象ファクトリに依存できます。あなたは責任を工場に移します。それでも、ファクトリ内でその依存関係を作成する必要があります。次の例は、解決策を示しています。
// Part of Composition Root
private class SomeObjectFactory : ISomeObjectFactory
{
private readonly Container container;
public SomeObjectFactory(Container container)
{
this.container = container;
}
public SomeObject Create(int someValue)
{
return new SomeObject(someValue,
this.container.GetInstance<IOtherDependency>()
);
}
}
これは機能Create
しますが、コンストラクターが変更されるたびにメソッドを変更する必要がありSomeObject
ます。
したがって、一般的に私のアドバイスは、目標が自動配線 (コンテナがすべての依存関係を注入する場所) を行うことである場合、同じコンストラクターでプリミティブ値 (int や string など) とサービスの依存関係を混在させないようにすることです。一部のコンテナーには、プリミティブ値を含む型を登録および解決するためのサポートが組み込まれていますが、常に、より多くのメンテナンスが必要で脆弱な DI 構成につながります。
代わりに、次のいずれかを試してください。
- プリミティブ値を、注入可能なクラスにラップします。つまり
IConnectionManager
、 a の代わりにan を注入しstring connectionString
ます。 - プリミティブ値をプロパティにプロモートします。Simple Injector を使用すると、 ( を使用して初期化デリゲートを登録することにより)明示的なプロパティ インジェクション
RegisterInitializer
を行うことができ、コンパイル時に検証可能なワイヤリングが可能になります。
このルールの唯一の例外は、ここに示すように、ある種のプリミティブ値を自動的に検出できるようにする、構成上の何らかの規則がある場合です。それでも、あなたのデザインをよく見なければならないと思います。同じプリミティブ (構成) 値が複数のサービスに注入される場合、抽象化が欠落している可能性があります。その場合は、#1 を適用してください。
ただし、このアドバイスは特に構成値に当てはまります。ランタイム値を扱っています。ただし、実行時の値を扱う場合は、プロパティを使用することもできます。
// Part of Composition Root
private class SomeObjectFactory : ISomeObjectFactory
{
private readonly Container container;
public SomeObjectFactory(Container container)
{
this.container = container;
}
public SomeObject Create(int someValue)
{
var instance = this.container.GetInstance<SomeObject>();
instance.SomeValue = someValue;
return instance;
}
}
プロパティにプロモートSomeValue
することで、コンテナが自動配線を使用できるようにしSomeObject
、 のランタイム値の注入でコンパイル時のサポートを有効にしますsomeValue
。
ただし、そのようなファクトリの使用は少し冗長に見えるかもしれませんし、他の人は代わりにFunc<T>
デリゲートを注入するかもしれません:
container.RegisterSingle<Func<int, SomeObject>>(someValue =>
{
var instance = this.container.GetInstance<SomeObject>();
instance.SomeValue = someValue;
return instance;
});
この場合、アプリケーション ロジックは、Func<int, SomeObject>
コンストラクターに注入できるデリゲートに依存できます。Func<int, SomeObject>
これにより、多くのセレモニーが削除されますが、そのままでは表現力が大幅に低下するため、アプリケーションの設計で表現力が失われるという欠点がありSomeObject Create(int someValue)
ます。
ただし、特定のケースでは、エンティティを解決しているようです。Mark Seemann がここで説明したように、これは最善の方法ではないかもしれません。さらに、ID を持つエンティティは通常、データベースから取得されるため、ランタイム ID を使用してフィードするエンティティをコンテナーに作成させることは、私には奇妙に思えます。
おそらくドメイン駆動設計を適用しているため、エンティティにこれらのサービスの依存関係が必要です。コンストラクターまたはプロパティの注入を行う代わりに、メソッドの注入を使用することを検討してください。エンティティのメソッドが必要とする依存関係をメソッド引数として追加するだけです。コマンド ハンドラからそのメソッドを呼び出すときに、これらの依存関係を渡すことができます。その場合、コマンド ハンドラーは従来の単純なコンストラクター インジェクションを引き続き使用できます。これを初めて見たとき (ジミー・ニルソンのプレゼンテーションだったと思います)、私が知っているすべてのことと矛盾しているように感じました。ただし、しばらくすると、これが実際には非常に優れたソリューションであることがわかり始めました (この特定のシナリオでは)。