2016-09-25 58 views
1

我知道我可以使用兒童容器。如果我有以下結構:如何從特定範圍隱藏組件註冊?

 parent container 
    /   \ 
child container 1  child container 2 

然後在「孩子1」我註冊的每個組件是從「孩子2」隱藏起來,而它們都可以從父容器使用共同的組件。我認爲這幾乎是我所需要的,但是我已經多次閱讀過,子容器是邪惡的,通常有更好的方法來實現相同的行爲。例如here剋日什托夫聲稱,該

Basically handler selectors and sub-resolvers give you all the power you need to handle scenarios where you would want to use child container instead. I think removing the child containers, and add some nicer support for contextual scoping of components would be the best solution.

是否有支持這一行動的例子?在閱讀相關文件後,我覺得我還處於黑暗中。我只是不明白如何使用自定義選擇器和子分解器來實現相同的行爲。

用例。我有以下組件的多個實例:我想用默認ArrayResolver的幫助以解決

class Component 
{ 
    public Component(ILayer[] layers, ...) 
    { 
     ... 
    } 
} 

。但是,對於Component的每個實例,我只想注入一個特定的註冊圖層子集,這是專門爲此組件註冊的。如果我不使用子容器,登記可能會是這樣的:

container.Register(Component.For<ILayer>.ImplementedBy<LayerA>() 
          .Named("Component1_LayerA")); 
container.Register(Component.For<ILayer>.ImplementedBy<LayerB>() 
          .Named("Component1_LayerB")); 
//etc... 
container.Register(Component.For<ILayer>.ImplementedBy<LayerB>() 
          .Named("Component2_LayerB")); 
container.Register(Component.For<ILayer>.ImplementedBy<LayerC>() 
          .Named("Component2_LayerC")); 
//etc... 
conatiner.Register(Component.For<Component>.Named("Component1")); 
conatiner.Register(Component.For<Component>.Named("Component2")); 

現在,當我打電話container.Resolve<Component>("Component1")我怎麼告訴溫莎只​​解決層,其名稱以「Component1_」開始?還是應該使用完全不同的方法?

+2

這是[這些情況,使DI容器失敗IMO](http://criticalsoftwareblog.com/index.php/2015/08/23/why-di-containers-fail-with-復對象的圖形/)。我建議你看看[Pure DI](http://blog.ploeh.dk/2014/06/10/pure-di/)。 –

回答

0

這裏是一個子解析器我通過試錯想出了:

class LayersResolver : ISubDependencyResolver 
{ 
    public LayersResolver(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, 
     DependencyModel dependency) 
    { 
     return dependency.TargetType == typeof(ILayer[]); 
    } 

    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, 
     DependencyModel dependency) 
    { 
     var result = _kernel.GetHandlers(typeof(ILayer)) 
          .Where(h => h.ComponentModel.Name.StartsWith(model.Name)) 
          //at this point it is not clear to me, whether I should call 
          //h.Resolve(context) 
          //or 
          //h.Resolve(context, contextHandlerResolver, model, dependency) 
          //or 
          //_kernel.Resolve<ILayer>(h.ComponentModel.Name) 
          //and what is the difference 
          .Select(h => _kernel.Resolve<ILayer>(h.ComponentModel.Name)) 
          .ToArray(); 
     return result; 
    } 

    private readonly IKernel _kernel; 
} 

它似乎正常工作,至少在我的問題簡化的例子。但是我無法確認這是對我的問題的最佳解決方案。正如Yacoub Massad在評論中提到的那樣,這可能是其中最好完全放棄容器的情況之一。

1

我認爲你的用例得到了溫莎城堡的很好的支持。您需要的功能是ServiceOverride。一個可能類似的問題是How to register same class twice with different dependencies

+0

在我的情況下'ILayer'實現由外部代碼提供,並且可以在'Component'註冊後註冊。我不知道實現類型或將會有多少層。它使得很難使用'DependsOn'方法 - 每次註冊新的'ILayer'時,我都必須以某種方式修改'Component'註冊。就我所見,它也不能與數組解析器一起工作。 –

+0

啊好的。我沒有注意到運行時註冊要求在第一位:) – Thuan