如何在特定范围内隐藏组件注册

本文关键字:隐藏 组件 注册 范围内 | 更新日期: 2023-09-27 18:08:35

我知道我可以使用子容器。如果我有以下结构:

        parent container
       /              '
child container 1     child container 2

那么我在"子1"中注册的每个组件都对"子2"隐藏,而它们都可以使用父容器中的公共组件。我认为这就是我所需要的,但是我在很多场合读到,子容器是邪恶的,通常有更好的方法来实现同样的行为。例如这里Krzysztof声称

基本上,处理程序选择器和子解析器为您提供了处理想要使用子容器的场景所需的所有功能。我认为删除子容器,并为组件的上下文范围添加一些更好的支持将是最好的解决方案。

有任何例子支持这一点吗?在阅读了相关文档后,我觉得我仍然是在黑暗中。我只是不明白如何使用自定义选择器和子解析器来实现相同的行为。

用例

。我有以下组件的多个实例:

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")时,我如何告诉Windsor只解析层,哪个名称以"Component1_"开头?或者我应该使用完全不同的方法?

如何在特定范围内隐藏组件注册

我认为温莎城堡很好地支持了您的用例。您需要的特性是ServiceOverride。一个可能类似的问题是如何用不同的依赖项注册同一个类两次

这是我通过反复试验得出的子解析器:

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在评论中提到的那样,这可能是最好完全放弃容器的情况之一。