When applying Dependency Injection and adhering to the Dependency Inversion Principle, the common advice is to program to interfaces, not implementations. That's why most of the time you'll see bindings that go from an abstraction to an implementation:
Bind<IWarrior>().To<Samurai>();
This means that components depend on IWarrior
at compile time, while you inject a Samurai
at runtime.
Under certain conditions, however, it makes sense to have mapping from a concrete component to itself. In other words, in case 'someone' requires a Samurai
, you supply it with that Samurai
.
The most prominent case is when resolving root types. Root types are the top of the dependency graph; root types are resolved directly from the container. All other components are direct or indirect dependencies of a root type.
Often you'll see that those root types are resolved by their concrete types and this happens, for instance, when dealing with UI frameworks. Examples of such are Web Forms Page
s, MVC Controller
s, Web API ApiController
s, etc.
Some DI containers allow concrete unregistered types to be resolved anyway (although in recent years several DI Containers for .NET have disabled the ability to resolve concrete unregistered types by default). This might lead you to believe that a self-binding is redundant, but that is not always the case. Adding such binding explicitly lets the container know about the existence of such binding. This has the advantage of using the container's diagnostic abilities (if present) to scan the object graphs for errors. In case of the absence of such feature, one can usually iterate the known registrations and do some verification inside a unit test. For such verification to be meaningful when the container's registrations are iterated over, all root types need to be registered in the container. Otherwise this verification process will result in false-negatives.
Another reason why you want to tell the DI container about a self-binding is when you need the type to be registered with a different lifestyle than the container's default lifestyle. Most containers will give you a Transient instance, in case the type isn't registered.