Update: Is there a way to achieve what I'm trying to do in an IoC framework other than Windsor? Windsor will handle the controllers fine but won't resolve anything else. I'm sure it's my fault but I'm following the tutorial verbatim and objects are not resolving with ctor injection, they are still null despite doing the registers and resolves. I've since scrapped my DI code and have manual injection for now because the project is time sensitive. Hoping to get DI worked out before deadline.
I have a solution that has multiple classes that all implement the same interface
As a simple example, the Interface
public interface IMyInterface {
string GetString();
int GetInt();
...
}
The concrete classes
public class MyClassOne : IMyInterface {
public string GetString() {
....
}
public int GetInt() {
....
}
}
public class MyClassTwo : IMyInterface {
public string GetString() {
....
}
public int GetInt() {
....
}
}
Now these classes will be injected where needed into layers above them like:
public class HomeController {
private readonly IMyInterface myInterface;
public HomeController() {}
public HomeController(IMyInterface _myInterface) {
myInterface = _myInterface
}
...
}
public class OtherController {
private readonly IMyInterface myInterface;
public OtherController() {}
public OtherController(IMyInterface _myInterface) {
myInterface = _myInterface
}
...
}
Both controllers are getting injected with the same interface.
When it comes to resolving these interfaces with the proper concrete class in my IoC, how do I differentiate that HomeController
needs an instance of MyClassOne
and OtherController
needs an instance of MyClassTwo
?
How do I bind two different concrete classes to the same interface in the IoC? I don't want to create 2 different interfaces as that breaks the DRY rule and doesn't make sense anyway.
In Castle Windsor I would have 2 lines like this:
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>());
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>());
This won't work because I will only ever get a copy of MyClassTwo
because it's the last one registered for the interface.
Like I said, I don't get how I can do it without creating specific interfaces for each concrete, doing that breaks not only DRY rules but basic OOP as well. How do I achieve this?
Update based on Mark Polsen's answer
Here is my current IoC, where would the .Resolve
statements go? I don' see anything in the Windsor docs
public class Dependency : IDependency {
private readonly WindsorContainer container = new WindsorContainer();
private IDependency() {
}
public IDependency AddWeb() {
...
container.Register(Component.For<IListItemRepository>().ImplementedBy<ProgramTypeRepository>().Named("ProgramTypeList"));
container.Register(Component.For<IListItemRepository>().ImplementedBy<IndexTypeRepository>().Named("IndexTypeList"));
return this;
}
public static IDependency Start() {
return new IDependency();
}
}
Java does not support "multiple inheritance" (a class can only inherit from one superclass). However, it can be achieved with interfaces, because the class can implement multiple interfaces. Note: To implement multiple interfaces, separate them with a comma (see example below).
So if you only use one implementation in your application after the application started, please register the implementation according to the configuration in DI container (Startup. Configure). If at application runtime, you need to choose from multiple implementations, you can use this solution without problem.
A class can implement multiple interfaces and many classes can implement the same interface.
A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one or more interfaces.
I hope you can use service overrides.
Ex.
container.Register(
Component.For<IMyService>()
.ImplementedBy<MyServiceImpl>()
.Named("myservice.default"),
Component.For<IMyService>()
.ImplementedBy<OtherServiceImpl>()
.Named("myservice.alternative"),
Component.For<ProductController>()
.ServiceOverrides(ServiceOverride.ForKey("myService").Eq("myservice.alternative"))
);
public class ProductController
{
// Will get a OtherServiceImpl for myService.
// MyServiceImpl would be given without the service override.
public ProductController(IMyService myService)
{
}
}
You should be able to accomplish it with named component registration.
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>().Named("One"));
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>().Named("Two"));
and then resolve them with
kernel.Resolve<IMyInterface>("One");
or
kernel.Resolve<IMyInterface>("Two");
See: To specify a name for the component
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With