2012-03-22 7 views
5

私は次のコードを持っている:コンストラクタ・インジェクションと`Func <>`をパラメータとして持つクラスを登録するには?

_container = new UnityContainer(); 
_container.RegisterType<IDownloader, Downloader>(); 
_container.RegisterType<INewObject, NewObject>(); 
_container.RegisterType<SearchViewModel>(); 

SearchViewModelクラス:

class SearchViewModel 
{ 
    private readonly Func<IDownloader> _downloaderFactory; 
    private readonly INewObject _newObject; 
    private IDownloader _downloader; 

    public SearchViewModel(Func<IDownloader> downloaderFactory, INewObject newObject) 
    { 
     _downloaderFactory = downloaderFactory; 
     _newObject = newObject; 
    }   
} 

に質問:パラメータとしてFun<>を持ってSearchViewModelを登録する方法を?

_container.RegisterType<SearchViewModel>(new InjectionConstructor(DownloaderFactory())); 

上記のコードはINewObjectなしでのみ動作します。

目標:解決InjectionConstructorと工場と自動的INewObject, INewObject2, INewObject3を解決(のようなパラメータなし:RegisterType<SearchViewModel>())。

それは可能ですか?多分交代ですか?

public interface IDownloaderFactory 
{ 
    IDownloader Create(); 
} 

その後、あなたは、単にインスタンスを解決するために、再度コンテナを使用して工場を表現するクラスを作成します。

+1

なぜINewObjectパラメータにSetter注入を使用しないのですか? – daryal

+0

SearchViewModelをFunc に依存させる理由を教えてください。それは漏れの抽象ではありませんか?私はあなたが直接IDownloaderのインターフェイスを注入すべきだと思う。 IDownloaderの具体的な実装は、工場の動作をカプセル化することができます。ここのコードサンプルを参照してください:http://stackoverflow.com/questions/9757953/can-any-of-existing-ioc-containers-create-the-lazy-proxy-classes-dynamically –

答えて

8

は私が問題を解決した:私が試したの前にあるため

_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i => 
      new Func<IDownloader> (() => _container.Resolve<IDownloader>()))); 
_container.RegisterType<SearchViewModel>(); 

新しいfuncが、鍵です。また

_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i => 
      _container.Resolve<IDownloader>())); 

IDownloaderFactoryの代わりFunc<IDownloader> downloaderFactoryを使用するためのより良い方法を。 IDownloaderFactoryはデリゲートをカプセル化できます。

また、デリゲートを工場内の依存関係として使用すると、壊れたComposition Rootよりも優れたソリューションと考えています。

2

ここで使用するために一般的に受け入れられたパターンは、抽象的な工場を宣言し、それが少しより明示的にすることです。

public class DownloaderFactory : IDownloaderFactory 
{ 
    private UnityContainer _Container; 
    public DownloaderFactory(UnityContainer container) 
    { 
     this._Container = container; 
    } 

    public IDownloader Create() 
    { 
     return this._Container.Resolve<IDownloader>(); 
    } 
} 

は、このアプローチを使用することで、より明示的であると、コンテナでもっとうまく演じても、それはまだ今あなたは自分のSearchViewModelクラスに小さな調整を必要とし、離れてあなたのアプリケーションとビジネスロジックからコンテナを保持します:

class SearchViewModel 
{ 
    private readonly IDownloaderFactory _downloaderFactory; 
    private readonly INewObject _newObject; 

    public SearchViewModel(IDownloaderFactory downloaderFactory, INewObject newObject) 
    { 
     _downloaderFactory = downloaderFactory; 
     _newObject = newObject; 

     Console.WriteLine(downloaderFactory.Create().GetHashCode()); 
     Console.WriteLine(downloaderFactory.Create().GetHashCode()); 
    } 

}

今、あなたはそれを見ることができるだけで動作し、毎回新しいインスタンスを作成します。次のようになり、コンテナの設定

あなたは工場出荷時には、このメソッドまたはThreadLocalのを使用して、同じインスタンスのいずれかを取得するようにして作業しているコンテナのインスタンスを登録する必要があり
 var container = new UnityContainer(); 
     container.RegisterType<IDownloader, Downloader>(); 
     container.RegisterType<INewObject, NewObject>(); 
     container.RegisterType<IDownloaderFactory, DownloaderFactory>(); 
     container.RegisterType<SearchViewModel>(); 
     container.RegisterInstance(container); 
     var model = container.Resolve<SearchViewModel>(); 

お知らせインスタンス化または何か。

注: もただのFuncアプローチを使用するか、ダウンローダを解決するための容器を使用して、あなたのクライアントでの望ましくない影響を引き起こす可能性があるという事実を警戒します。たとえば、デフォルトでコンテナがダウンローダのオブジェクトに一時的に設定されている場合は、毎回新しいインスタンスが作成されます。コンテナの寿命を延ばすと、クライアントは毎回同じインスタンスを取得する可能性があります。そのような場合、工場でダウンローダオブジェクトを手動で構築し、ダウンローダの引数に対してのみコンテナを使用する方が良いでしょう。

関連する問題