Ninject supports four patterns for injection, which are listed here. All injections are controlled by the
"[Inject]" attribute. Each kind of injection has its own benefits and detriments, and you may find each to be useful in different circumstances.
Note! You will need to add a reference to Ninject.Core.dll to your project as well as add using/import Ninject.Core in your source to build the following examples.
Constructor Injection
The first (and arguably best) type is constructor injection. When activating an instance of a type, if the type has a constructor with an
"[Inject]" attribute, Ninject will try to activate an object for each of the constructor's parameters.
C#:
class Samurai {
private readonly IWeapon _weapon;
[Inject]
public Samurai(IWeapon weapon) {
_weapon = weapon;
}
public void Attack(string target) {
_weapon.Hit(target);
}
}
VB.NET:
Public Class Samurai
Private ReadOnly _sword As IWeapon
<Inject()> _
Public Sub New(ByVal weapon As IWeapon)
_sword = weapon
End Sub
Public Sub Attack(ByVal target As String)
_sword.Hit(target)
End Sub
End Class
When in doubt, use constructor injection, because it lets you inject multiple dependencies at once, and add the
readonly keyword to the fields that hold the injected values. (Using
readonly is a matter of taste, and is entirely up to you. Ninject doesn't mind either way.)
An important note! You can only have one constructor of your type marked with an
"[Inject]" attribute. If you put an
"[Inject]" attribute on more than one constructor, Ninject will throw a
NotSupportedException the first time an instance of the type is requested.
You also have the option to leave off the
"[Inject]" attribute completely. This can help if you don't have access to the source code of a class, but you still want to inject dependencies into it. Here's the logic Ninject follows to choose which constructor to call, if none have an
"[Inject]" attribute:
- If the type only has a single constructor, Ninject will call it.
- If the type has more than one constructor, but has a default (parameterless) constructor available, Ninject will call it. (This also applies to types that have no explicit constructors defined.)
Property Injection
Here's an example of our same
Samurai class using property injection. Unlike constructor injection, you can have multiple properties decorated with an
"[Inject]" attribute.
Be careful! The order of property injection is not deterministic, meaning there is no way to tell in which order Ninject will inject their values in. (However, you can also request notification when all injections are complete by implementing either the the
IInitializable or the
IStartable interface, discussed later.)
C#:
class Samurai {
private IWeapon _weapon;
[Inject]
public IWeapon Weapon {
get { return _weapon; }
set { _weapon = value; }
}
public void Attack(string target) {
_weapon.Hit(target);
}
}
VB.NET:
Public Class Samurai
Private _sword As IWeapon
<Inject()> _
Public Property Weapon() As IWeapon
Get
Return _sword
End Get
Set(ByVal Value As IWeapon)
_sword = Value
End Set
End Property
Public Sub Attack(ByVal target As String)
_sword.Hit(target)
End Sub
End Class
Method Injection
Here's method injection. As with constructor injection, you can also inject multiple values at once via the same method. You can also have multiple methods decorated with the
"[Inject]" attribute. They will all be called, but as with property injection, there is no guarantee on which order they will receive their injections.
C#:
class Samurai {
private IWeapon _weapon;
[Inject]
public void Arm(IWeapon weapon) {
_weapon = weapon;
}
public void Attack(string target) {
_weapon.Hit(target);
}
}
VB.NET:
Public Class Samurai
Private _sword As IWeapon
<Inject()> _
Private Sub Arm(ByVal weapon As IWeapon)
_sword = weapon
End Sub
Public Sub Attack(ByVal target As String)
_sword.Hit(target)
End Sub
End Class
Field Injection
And finally, here's field injection. Same rules apply: multiple fields can have
"[Inject]" attributes, but the order of their injections is not deterministic.
C#:
class Samurai {
[Inject] private IWeapon _weapon;
public void Attack(string target) {
_weapon.Hit(target);
}
}
VB.NET:
Public Class Samurai
<Inject()> Private _sword As IWeapon
Public Sub Attack(ByVal target As String)
_sword.Hit(target)
End Sub
End Class
Although its simplicity is tempting, you should generally try to avoid using field injection, since the value can then only be set via Ninject. This makes unit testing much more complex, since sometimes it's easiest to use dependency injection by hand to inject mock objects into your unit tests. (Unit testing with Ninject is covered in more depth later.)
Continue reading:
Activation Behaviors