How to register same class twice with different de

2019-06-14 11:16发布

I would like to configure Castle Windsor to create two components of same type (Foo -> IFoo), but with different constructor inputs. I would also later like to consume both components when creating another component (type Bar - see code below).

public interface IFoo { }

public class Foo : IFoo
{
    private string _prop;

    public Foo(string prop)
    {
        _prop = prop;            
    }
}

public class Bar
{
    private IFoo _fooAbc;
    private IFoo _foo123;

    public Bar(IFoo fooAbc, IFoo foo123)
    {
        _foo123 = foo123;
        _fooAbc = fooAbc;
    }
}

In component installer I tried registering components like this:

public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
                            .BasedOn<IFoo>().WithServiceBase()
                            .ConfigureFor<Foo>(c => c.DependsOn(Dependency.OnValue<string>("abc")).Named("fooAbc"))
                            .ConfigureFor<Foo>(c => c.DependsOn(Dependency.OnValue<string>("123")).Named("foo123")));

        container.Register(Component.For<Bar>());   //?? specify which service to use
    }

But castle throws an registration exception. So how can I configure two instances of Foo, one with "abc" and another with "123" dependency? Also I would later like to correctly assign them when constructing Bar, so that fooAbc is used as first constructor input, and foo123 as second. My end goal would be to successfully resolve Bar.

1条回答
Melony?
2楼-- · 2019-06-14 11:24

I'm not sure if this is closer to what you're asking for, but, you can use ServiceOverride.ForKey to specify which parameters map to which names:

Component.For<Bar>().ImplementedBy<Bar>().
    DependsOn(ServiceOverride.ForKey("fooAbc").Eq("abc")).
    DependsOn(ServiceOverride.ForKey("foo123").Eq("123"))
);

Alternatively, not a direct answer, but an option you have is to resolve an IEnumerable<IFoo>. This is a good option if you actually have an arbitrary number of IFoo to resolve.

If you change the definition of Bar to accept an IEnumerable

public class Bar
{
    private readonly IEnumerable<IFoo> _foos;

    public Bar(IEnumerable<IFoo> foos)
    {
        _foos = foos;
    }
}

Then to register and resolve. You need to add the Resolve before you do the registrations.

var container = new WindsorContainer();

container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true));

container.Register(
    Component.For<IFoo>().Instance(new Foo("abc")).Named("abc"),
    Component.For<IFoo>().Instance(new Foo("123")).Named("123"),
    Component.For<Bar>().ImplementedBy<Bar>());
查看更多
登录 后发表回答