次のコードでIRespository
を(名前を付けて)2回登録しています。
// Setup the Client Repository
IOC.Container.RegisterType<ClientEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
("Client", new InjectionConstructor(typeof(ClientEntities)));
// Setup the Customer Repository
IOC.Container.RegisterType<CustomerEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
("Customer", new InjectionConstructor(typeof(CustomerEntities)));
IOC.Container.RegisterType<IClientModel, ClientModel>();
IOC.Container.RegisterType<ICustomerModel, CustomerModel>();
しかし、(IRepository
を使用するために)これを解決したいときは、次のように手動で解決する必要があります。
public ClientModel(IUnityContainer container)
{
this.dataAccess = container.Resolve<IRepository>(Client);
.....
}
私がやりたいのは、コンストラクタで解決することです(IUnityContainer
のように)。解決する名前付きの型を指定する方法が必要です。
このようなもの:(注:実際のコードではありません)
public ClientModel([NamedDependancy("Client")] IRepository dataAccess)
{
this.dataAccess = dataAccess;
.....
}
偽のコードを機能させる方法はありますか?
API、属性、または構成ファイルを使用して、名前の有無に関係なく依存関係を構成できます。上記でXMLについて言及しなかったので、APIを使用していると仮定します。
名前付き依存関係を解決するようにコンテナに指示するには、InjectionParameter
オブジェクトを使用する必要があります。 ClientModel
の例では、次を実行します。
container.RegisterType<IClientModel, ClientModel>(
new InjectionConstructor( // Explicitly specify a constructor
new ResolvedParameter<IRepository>("Client") // Resolve parameter of type IRepository using name "Client"
)
);
これは、コンテナに「ClientModel
を解決するとき、単一のIRepository
パラメータを取るコンストラクタを呼び出します。そのパラメータを解決するとき、タイプに加えて「Client」という名前で解決します。」
属性を使用したい場合、サンプルはほとんど機能します。属性名を変更するだけです。
public ClientModel([Dependency("Client")] IRepository dataAccess)
{
this.dataAccess = dataAccess;
.....
}
これは非常に遅い応答ですが、質問は引き続きGoogleに表示されます。
とにかく、5年後...
私は非常にシンプルなアプローチをしています。通常、「名前付き依存関係」を使用する必要があるのは、何らかの戦略パターンを実装しようとしているためです。その場合、UnityとStrategyResolver
と呼ばれるコードの残りの部分との間に間接的なレベルを作成するだけで、Unityに直接依存しません。
public class StrategyResolver : IStrategyResolver
{
private IUnityContainer container;
public StrategyResolver(IUnityContainer unityContainer)
{
this.container = unityContainer;
}
public T Resolve<T>(string namedStrategy)
{
return this.container.Resolve<T>(namedStrategy);
}
}
使用法:
public class SomeClass: ISomeInterface
{
private IStrategyResolver strategyResolver;
public SomeClass(IStrategyResolver stratResolver)
{
this.strategyResolver = stratResolver;
}
public void Process(SomeDto dto)
{
IActionHandler actionHanlder = this.strategyResolver.Resolve<IActionHandler>(dto.SomeProperty);
actionHanlder.Handle(dto);
}
}
登録:
container.RegisterType<IActionHandler, ActionOne>("One");
container.RegisterType<IActionHandler, ActionTwo>("Two");
container.RegisterType<IStrategyResolver, StrategyResolver>();
container.RegisterType<ISomeInterface, SomeClass>();
さて、これのいいところは、将来新しい戦略を追加するときに、StrategyResolverに再び触れる必要がないことです。
とても簡単です。非常にきれいで、Unityへの依存を最小限に抑えました。 StrategyResolverに触れるのは、起こりそうにないコンテナテクノロジーを変更することだけです。
お役に立てれば!
編集:サービスのコンストラクターでDependency
属性を使用すると、実際にはUnityに強い依存関係があるため、受け入れられた答えがあまり好きではありません。 Dependency
属性は、Unityライブラリの一部です。その時点で、どこでもIUnityContainer
依存関係を渡すこともできます。
私は、サービスクラスを、外部ライブラリに全面的に依存するのではなく、完全に所有するオブジェクトに依存させることを好みます。また、Dependency
属性を使用すると、コンストラクターの署名が簡潔で単純になります。
さらに、この手法により、コンストラクター、アプリケーション構成ファイルで名前付き依存関係をハードコーディングしたり、設計時に使用する名前付き依存関係を知る必要があるInjectionParameter
を使用したりすることなく、実行時に名前付き依存関係を解決できます時間。
編集(2016-09-19):疑問に思われるかもしれませんが、IUnityContainer
コンストラクター署名に示されているように、StrategyResolver
を依存関係として要求するときに、コンテナーは自分自身を渡すことを知っています。
編集(2018-10-20):ファクトリを使用するだけの別の方法があります:
public class SomeStrategyFactory : ISomeStrategyFactory
{
private IStrategy _stratA;
private IStrategy _stratB;
public SomeFactory(IStrategyA stratA, IStrategyB stratB)
{
_stratA = stratA;
_stratB = stratB;
}
public IStrategy GetStrategy(string namedStrategy){
if (namedStrategy == "A") return _stratA;
if (namedStrategy == "B") return _stratB;
}
}
public interface IStrategy {
void Execute();
}
public interface IStrategyA : IStrategy {}
public interface IStrategyB : IStrategy {}
public class StrategyA : IStrategyA {
public void Execute(){}
}
public class StrategyB : IStrategyB {
public void Execute() {}
}
使用法:
public class SomeClass : ISomeClass
{
public SomeClass(ISomeStrategyFactory strategyFactory){
IStrategy strat = strategyFactory.GetStrategy("HelloStrategy");
strat.Execute();
}
}
登録:
container.RegisterType<ISomeStrategyFactory, SomeStrategyFactory>();
container.RegisterType<IStrategyA, StrategyA>();
container.RegisterType<IStrategyB, StrategyB>();
container.RegisterType<ISomeClass, SomeClass>();
この2番目の提案は同じものですが、工場設計パターンを使用しています。
お役に立てれば!
ParameterOverridesを使用できるはずです
var repository = IOC.Container.Resolve<IRepository>("Client");
var clientModel = IOC.Container.Resolve<ClientModel>(new ParameterOverrides<ClientModel> { {"dataAccess", repository } } );
編集:なぜあなたはUnityContainerを回しているのか分かりません-個人的に、私たちはコンストラクタ自体に依存関係を注入します(これは私が見たものから「正常」です)。ただし、RegisterTypeメソッドとResolveメソッドで名前を指定できます。
IOC.Container.RegisterType<IRepository, GenericRepository>("Client");
IOC.Container.Resolve<IRepository>("Client");
その名前に対して登録したタイプが表示されます。
これをしないでください-class ClientRepository : GenericRepository { }
およびタイプシステムを利用します。