Consider the following scenario of services and components in a sample C# console application
public interface IService { }
public class FooService: IService { }
public class BarService: IService { }
public class BuzzService: IService { }
public class AwesomeService: IService { }
public class Consumer
{
public Consumer(IEnumerable<IService> services)
{
// do some initilization work here...
}
}
public class AnotherConsumer
{
public AnotherConsumer(IEnumerable<IService> services)
{
// do some initilization work here...
}
}
Let's imagine to do the following registrations inside the composition root:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true));
container.Register(Component.For<IService>().ImplementedBy<FooService>());
container.Register(Component.For<IService>().ImplementedBy<BarService>());
container.Register(Component.For<IService>().ImplementedBy<BuzzService>());
container.Register(Component.For<IService>().ImplementedBy<AwesomeService>());
container.Register(Component.For<Consumer>());
container.Register(Component.For<AnotherConsumer>());
// consumer got injected all 4 different implementations of IService
// due to CollectionResolver
var consumer = container.Resolve<Consumer>();
// anotherConsumer got injected all 4 different implementations of
// IService due to CollectionResolver
var anotherConsumer = container.Resolve<AnotherConsumer>();
This kind of scenario works fine and I did so several times.
What if, for some reason, I would like to inject inside the constructor of Consumer class only two different implementations of IService, for instance only FooService and BarService (while still continuing to inject all the available implementations of IService inside the constructor of AnotherConsumer) ?
Is there an elegant way to do so?
I grabbed my copy of the first edition of Dependency Injection Principles, Practices, and Patterns. It contains a complete chapter on Castle Windsor and discusses this exact scenario. The trick is to do two things:
.Named(string)
Consumer
using .ServiceOverrides(object)
The following code sample is almost straight out of the book (with the names replaced with your examples):
container.Register(Component
.For<IService>()
.ImplementedBy<FooService>()
.Named("Foo"));
container.Register(Component
.For<IService>()
.ImplementedBy<BarService>()
.Named("Bar"));
container.Register(Component
.For<IService>()
.ImplementedBy<BuzzService>()
.Named("Buzz"));
container.Register(Component
.For<IService>()
.ImplementedBy<AwesomeService>()
.Named("Awesome"));
container.Register(Component
.For<Consumer>()
.ServiceOverrides(new
{
services = new[] { "Foo", "Bar" }
}));
container.Register(Component.For<AnotherConsumer>());
var consumer = container.Resolve<Consumer>();