UnityのResolve()メソッドにコンストラクターパラメーターを渡すことはできますか?


91

依存関係の注入にMicrosoftのUnityを使用しており、次のようなことをしたいと思っています。

IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);

RepositoryAそして、RepositoryBの両方を取るコンストラクタ持っているIDataContextパラメータを、と私はUnityが、私はそれを渡すことをコンテキストにリポジトリを初期化したいです。また、IDataContextがUnityに登録されていないことにも注意してください(の3つのインスタンスは必要ありませんIDataContext)。

回答:


71

今日、彼らはこの機能を追加しました:

ここの最新のドロップにあります:

http://unity.codeplex.com/SourceControl/changeset/view/33899

ここでの議論:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

例:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"


5
リンクunity.codeplex.com/SourceControl/changeset/view/33899はアクティブではありません
M.Kumaran

2
「クラス 'Microsoft.Practices.Unity.ParameterOverrides'には型パラメーターがありません。」Unity 3.5を使用しています。このコードは古いバージョンのUnityでのみ有効ですか?
トーマスレベスク2014

わたしにはできる。注:クラスには、「name」パラメーターと「address」パラメーターを持つパラメーター化されたコンストラクターが必要です。 Foo(string name, int address) { ... }
adun

Unity 2.1の使用: container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2セント>

後でコンテキストだけではなく多かれ少なかれ必要な別のサービスを使用することにした場合はどうでしょうか。

コンストラクターパラメーターとIoCの問題は、パラメーターが、サービスインターフェイスが定義するコントラクトの一部ではなく、最終的には使用される具象型に関連付けられることです。

私の提案は、コンテキストも解決することであり、Unityはその3つのインスタンスを構築しないようにする方法を持っている必要があるか、またはオブジェクトを構築する方法があるファクトリサービスを検討する必要があると思います。

たとえば、従来のデータベースにまったく依存せず、代わりにXMLファイルを使用してテスト用のダミーデータを生成するリポジトリを構築するとしたらどうでしょうか。XMLコンテンツをそのコンストラクターにどのようにフィードしますか?

IoCはデカップリングコードに基づいており、具体的な型への引数の型とセマンティクスを結び付けることにより、実際にデカップリングを正しく行っていないため、依存関係がまだ残っています。

「このコードは、このインターフェイスを実装している限り、あらゆるタイプのリポジトリと通信できます。ああ、データコンテキストを使用します。」

これで、他のIoCコンテナーがこれをサポートしていることがわかりました。私自身の最初のバージョンにもそれがありましたが、私の意見では、解決策には属していません。

</ 2セント>


3
私はあなたの意見を理解して同意しますが、RepositoryAとRepositoryBのインスタンスが同じIDataContextを持つ必要があります。これは、RepositoryCとは異なる必要があります。また、IRepositoryAとIRepositoryBにはIDataContextのプロパティがあることに注意してください。サンプルコードを少し更新します。
NotDan 2009

2
素晴らしい点。文字列パラメーターをコンストラクターに追加しようとしていましたが、この点を確認した後、本格的なオブジェクトにすることにしました。この時点では文字列のみで構成されていますが、さらに便利なプロパティを追加する方法はすでにわかります
Santosh Benjamin

9

みんなありがとう...私は「存在する」の投稿に似ています。下記参照:

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });

5

ResolvedParameter <T>( "name")内のインジェクションアーキテクチャに応じて、InjectionConstructor / InjectionProperty / InjectionMethodを使用して、コンテナに事前登録されたオブジェクトのインスタンスを取得できます。

あなたの場合、このオブジェクトは名前で登録する必要があり、同じインスタンスでは、LifeTimeManagerとしてContainerControlledLifeTimeManager()が必要です。

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");

  var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));

4
このコードでよろしいですか?これは、コンパイルされません... ResolveのコレクションをとりResolverOverride、かつInjectionConstructorではありませんResolverOverride
トーマスレベスク2014

うんそれは間違って見えます。団結はそれをそのように設計するべきでしたが。パラメータ名を変更するとすべてが壊れる
フランクQ.

3

非常に短い答えは:いいえ。Unityは現在、定数または注入されていないパラメーターをコンストラクターに渡す方法がありません。私見はそれが欠けている最大の最大のものですが、それは省略ではなく設計によるものだと思います。

Jeff Fritzが指摘するように、理論的には、さまざまなタイプに注入するコンテキストインスタンスを認識するカスタムライフタイムマネージャーを作成できますが、これは、最初にUnityまたはDIを使用する目的を未然に防ぐハードコーディングのレベルです。

完全なDIから少し戻って、独自のデータコンテキストを確立する責任をリポジトリの実装に持たせることができます。コンテキストインスタンスは引き続きコンテナから解決できますが、どちらを使用するかを決定するロジックは、リポジトリの実装に移動する必要があります。それは確かにそれほど純粋ではありませんが、問題を取り除くでしょう。


1

あなたが使用できる別の代替手段(それが良い習慣であるかどうかは本当にわかりません)は、2つのコンテナーを作成し、それぞれのインスタンスを登録することです。

IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context


//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance

これも役に立てば幸い


0

NotDan、lassevkへのコメントであなた自身の質問に答えたかもしれません。

まず、LifetimeManagerを使用して、Unityが作成するIDataContextのライフサイクルとインスタンス数を管理します。
http://msdn.microsoft.com/en-us/library/cc440953.aspx

ように聞こえるContainerControlledLifetimeManagerオブジェクトはあなたが必要とするインスタンス管理を提供します。そのLifetimeManagerを配置すると、UnityはIDataContext依存関係を必要とするすべてのオブジェクトにIDataContextの同じインスタンスを追加する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.