2017-01-25 11 views
1

オブジェクトのコンストラクタにLazyを入れ、Xがコンテナに登録されていないと、依存性解決の例外が発生します。autofacオプション/遅延依存関係

なぜこの例外が発生しますか?実行時にコンポーネントを選択できないため、私はそれを嫌いです。例のユースケース:

class Controller 
{ 
    public Controller(Lazy<A> a, Lazy<B> b) { /* (...) */ } 

Lazy<A> a; 
Lazy<B> b; 

public IActionResult Get(){ 
    if(someConfig) 
    return Json(a.Value.Execute()); 
    else 
    return Json(b.Value.Execute()); 
} 
} 

私はB.私のプログラムは、Bを使ったことがない場合であっても失敗し、両方のコンポーネントを登録する必要があり、そうします。私はBをオプションにしておきたいが、それでもオートファックで管理している。

コンポーネントのリストがあり、1つしか使用しない場合は、これはさらに大きな問題です。例:

class Controller 
{ 
    Controller(IEnumerable<Component> components) { /* (...) */ } 

    IActionResult Get() 
    { 
     return components.First(n => n.Name == configuredComponent).Execute(); 

    } 

} 

何も登録されていないことはもうなくなりましたが、それでもすべてが構築されています。また、使用するのは面倒です。あなたはLazy<T>コンポーネントへの参照を追加した場合

答えて

7

は、Autofacは、あなたはそれをを解決したいはずです実行される内部関数を作成する方法(基本的に)知っていてもいない決意それを行うあなたの場合。

基本的には、メモリでこれを作成できるようにする必要があります。

var lazy = new Lazy<T>(() => scope.Resolve<T>()); 

Autofacを登録する解決するために、あなたが望むすべてのものが必要です。それはあなたが即座に物事を登録させることはありません - それは明示的でなければなりません。だからあなたがやろうとしていることはうまくいきません。

代わりに、1つのインターフェイスとそのインターフェイスの2つの異なる実装を使用します。設定値に基づいて登録を変更します。

var builder = new ContainerBuilder(); 
if(someConfig) 
{ 
    builder.RegisterType<A>().As<IService>(); 
} 
else 
{ 
    builder.RegisterType<B>().As<IService>(); 
} 

コントローラで、具体的なクラスではなくインターフェイスを注入します。

public MyController(Lazy<IService> service) 

使用のコンポーネントのmetadataまたはkeyed servicesのようなあなたができる他のオプションもあります。たとえば、構成に基づいてメタデータを追加し、それを使用して解決できます。コントローラで

builder.RegisterType<A>() 
     .As<IService>() 
     .WithMetadata("Name", "a"); 
builder.RegisterType<B>() 
     .As<IService>() 
     .WithMetadata("Name", "b"); 

、あなたはそれらの辞書取得したい:

public MyController(IEnumerable<Meta<IService>> services) 
{ 
    var service = services.First(s => s.Metadata["Name"].Equals(someConfig); 
} 

非常に短い例が、the docs show a lot moreです。

いずれにしても、インターフェイスは本当に成功の鍵となります。具体的なクラスを使用しているだけの場合は、クラスを使用するかどうかにかかわらず登録する必要があります。