Reputation: 133
I have taken the reference of this example from the link below.
http://blog.prabir.me/post/Dependency-Injection-%28DI%29-e28093-Hello-World-with-Ninject.aspx
using Ninject.Modules;
using Prabir.NinjectSample.Provider;
using Prabir.NinjectSamples.Providers.ConsoleWriter;
using Prabir.NinjectSample.Providers.MessageBoxWriter;
namespace Prabir.NinjectSample.ConsoleApplication
{
public class XDocModule : NinjectModule
{
public override void Load()
{
Bind<IWriter>().To<ConsoleWriter>();
Bind<XDoc>().ToSelf().InSingletonScope();
}
}
}
In the Load()
method, ConsoleWriter
is being wired up with IWriter
. It looks static and hardcoded. i.e. every time I call IWriter
, it will initialize ConsoleWriter
. What if I want to use MessageBoxWriter
as well. I will have to change the code in Load()
method to achieve that.
Am I missing anything or it is how Ninject behaves?
Furthermore, Load()
method will be called by all types of wiring up. In some other class, I might need to wire ConsoleReader
with IReader
. In that case, the same
Bind<IWriter>().To<ConsoleWriter>()
Bind<XDoc>().ToSelf().InSingletonScope()
will also be hit. Is this the expected way of Ninject?
Let me explain my question in more details. Lets say I have an interface given below.
public interface IVehicle
{
PrintSpecification();
}
I have three classes implementing above interface. They could be as shown.
public class Car implements IVehicle
{
public void PrintSpecification()
{ Console.WriteLine("Specification for Car");}
}
public class Bus implements IVehicle
{
public void PrintSpecification()
{ Console.WriteLine("Specification for Bus");}
}
public class Truck implements IVehicle
{
public void PrintSpecification()
{ Console.WriteLine("Specification for Truck");}
}
Now in my main program, I will have something like this. Here I have used new operator to create three concrete implementations of Car, Bus and Truck. I have to display the specification of all three vehicles. Now I wonder how do I write my Ninject codes so that there is no dependency of the concrete classes.
Public static void main()
{
IVehicle v1=new Car();
IVehicle v2=new Bus();
IVehicle v3=new Truck();
v1.PrintSpecification();
v2.PrintSpecification();
v3.PrintSpecification();
}
Upvotes: 0
Views: 1544
Reputation: 2314
Your second question can be solved like this
In your ninject module
Bind<IVehicle>().To<Car>();
Bind<IVehicle>().To<Bus>();
Bind<IVehicle>().To<Truck>();
Bind<IVehicleCarPark>().To<CarPark>();
In a class which is retrieved with ninject
public class CarPark : IVehicleCarPark
{
Ctor(IEnumerable<IVehicle> vehicles) {
// vehicles will be autoresolved
}
}
Upvotes: 0
Reputation: 5666
Module loading should be done once on the application startup (or you can load modules dynamically per request - when it is needed, but it is not probably your case).
If you want to use various implementations of your interface on different places you can use conditional binding.
Conditional binding:
Bind<IWriter>().To<ConsoleWriter>().When(x=> ReturnTrueWhenConditionMet());
Or you can use naming and NamedAttribute
:
Named attribute:
Binding
Bind<IWriter>().To<ConsoleWriter>().Named("ConsoleWritter");
Constructor of class where ConsoleWritter
will be injected.
public MyClassWithConcoleWritter([Named("ConsoleWritter")] IWriter writer)
{
}
Problem with NamedAttribute
is that it will tie you to Ninject in your bussines classes, so there would be problem to easy switch the IOC container if you need to do so.
However there are even more options how to do conditional binding. See this document for more information - Contextual binding.
Upvotes: 2