2016-09-25 4 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.

Есть ли какие-либо примеры, которые поддерживают это? Прочитав соответствующую документацию, я чувствую, что я все еще в темноте. Я просто не вижу, как добиться такого же поведения с помощью пользовательских селекторов и субревизоров.

Use case. У меня есть несколько экземпляров следующего компонента:

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

, которые я хочу, чтобы решить с помощью умолчанию ArrayResolver. Однако для каждого экземпляра 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; 
} 

Это, кажется, правильно работает, по крайней мере, на упрощенном примере в моем вопросе. Однако я не могу подтвердить, что это лучшее решение моей проблемы. Как упоминал Якуб Массад в комментариях, это может быть одним из тех случаев, когда лучше всего отказаться от контейнера.

1

Я думаю, что ваш прецедент хорошо поддерживается Виндзорским замком. Необходимая функция - ServiceOverride. Возможно, аналогичный вопрос: How to register same class twice with different dependencies

+0

В моем случае реализации 'ILayer' поставляются внешним кодом, и они могут быть зарегистрированы после регистрации« Component ». Я не знаю типы реализации или сколько слоев будет. Это затрудняет использование метода DependsOn - мне нужно как-то модифицировать регистрацию «Component» каждый раз, когда будет зарегистрирован новый «ILayer». Насколько мне известно, он также не работает с резольвером массива. –

+0

ах ок. Я не заметил, что требование регистрации во время выполнения в первую очередь :) – Thuan

 Смежные вопросы

  • Нет связанных вопросов^_^