4

I have seen this question Still need help understanding why Ninject might be better than manual DI but I am still confused by Ninject's usefulness...

I understand that this code...

class Samurai
{
    readonly IWeapon weapon;

    [Inject]
    public Samurai(IWeapon weapon)
    {
        this.weapon = weapon;
    }

    public void Attack(string target) 
    {
        this.weapon.Hit(target);
    }
}

... Will produce the following "dynamic method that (basically) looks like this:"

delegate(IWeapon weapon)
{
    return new Samurai(weapon);
}

How is this useful at all? Without Ninject, I can still do this (as per the Ninject docs "Dependency Injection By Hand" - No Ninject):

class Program
{
    public static void Main() 
    {
        var warrior1 = new Samurai(new Shuriken());
        var warrior2 = new Samurai(new Sword());
        warrior1.Attack("the evildoers");
        warrior2.Attack("the evildoers");
    }
}

What does using Ninject provide for me that I can't do by just following basic principals of loose coupling? Thanks for helping me understand.

Community
  • 1
  • 1
user1477388
  • 20,790
  • 32
  • 144
  • 264

3 Answers3

3

Darin's answer covers the most significant benefits of using a DI framework, but here's something that I found helpful when using a DI container. Suppose you have an object with these service dependencies:

public class Order : IOrder
{
    public Order(IOrderService orderSvc, ICustomerService custSvc)
    {
        // constructor logic
    }
}

Your code could look something like this:

var order = new Order(new OrderService(), new CustomerService()); // manual
or
var order = kernel.Resolve<IOrder>(); // using a DI container

This is working fine and well. Now, all of a sudden, your requirements have changed. Order now needs a shipping service:

public Order(IOrderService orderSvc, 
    ICustomerService custSvc, IShippingService svc)
{
    // constructor logic
}

Imagine you have 10 different places throughout your program where you manually create an Order. If you were handling the injection yourself, you have to find all 10 of those locations in code where you are creating an order and modify them. Doing this 10 times could be a lot of work!

var order = new Order(new OrderService(), new CustomerService(), new ShippingService());

However, with a DI container, once you register a binding, your code in all those 10 places looks like this:

var order = kernel.Resolve<IOrder>();

See how it is the same as before? You didn't have to change anything! All those 10 places where you resolve an order won't change** whether you add 1 dependency or 100. So it can help keep you from having to modify existing code as new dependencies are needed.

** This won't always be the case, but this is a simplified example to show one of the additional benefits that nobody talks much about.

hawkke
  • 4,242
  • 1
  • 27
  • 23
  • Thanks this is close to what I was looking for - a practical example of a benefit provided by a DI framework. However, whenever I instantiate an object, it will often have specific data in the constructor, so I don't see how calling a generic `kernel.Resolve();` would help when I need to call something like `new Order(myOrder, myCustomerService, myShippingService);` right? – user1477388 Sep 13 '13 at 13:01
  • 1
    @user1477388 That depends on the DI framework on how its done. Say Order needs an order ID parameter in the constructor. For Ninject, it looks something like this: `kernel.Get(new ConstructorArgument("orderId", orderId))` or along those lines. If you need to provide non-resolvable parameters, you'd have to modify all locations where you call `kernel.Get()`. – hawkke Sep 13 '13 at 14:18
  • So here's my thought then; If you have that many places where you would need to update something to where DI frameworks benefit you, does that not imply you actually aren't following DI principles? The whole concept is that one single service takes care of everything and you just subscribe to that service, our codebase is setup such that you only ever need to update one place if you need to change everything around, so for me it just seems like you're adding a whole layer on top of your code to make it DI friendly to make up for it not being architected to be DI friendly. – Trevor Hart Apr 19 '17 at 18:34
1

What does using Ninject provide for me that I can't do by just following basic principals of loose coupling?

  • Fewer lines of code in the Composition Root
  • A standard container for handling your object lifetimes
  • Many plugins for injection in specific contexts such as classic WebForms, ASP.NET MVC, ASP.NET Web API
  • Possibility to automatically dispose your IDIsposable objects
  • ...

All things that you should be handling manually otherwise. This being said, the DI framework is of little importance. It should be fast and offer the specific features you need for your application. But the DI framework should absolutely in no way influence the way you are designing your code and the different layers in your application in a loosely coupled manner (programming against interfaces and abstract classes to weaken the coupling between the different layers of your application).

So think of the DI framework as something that intervenes only in the Composition Root of your application and as a framework that you could replace in a blink of an eye with a different framework or even manually handling your object lifetimes.

For example the code you have shown in your question is very bad as it ties your layers to a specific DI framework. This [Inject] attribute over there is like a cancer. It means that your application code relies on a specific DI framework.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks for your answer. I am reading through http://manning.com/seemann/DIi.NET_sample_ch01.pdf and trying to get better understanding. What would really be helpful to me is something as practical as "here is code that you would have without Ninject" and "here is **better** code that you would have WITH Ninject." I just can't see how/where this is beneficial yet... Still trying! – user1477388 Sep 12 '13 at 20:19
  • You use NiNject in what is called the Composition Root of your application (Read the link in my answer to better understand what a Composition Root is). Basically a DI framework such as Ninject provides you with a nice DSL for describing your object graph dependencies and lifetime which would have been possible with lots of manual code and `new` statements otherwise. Not to mention the lifetime. In complex applications you want to have some dependencies as singleton and other as transient lieftime. Also take advantage of the specific extensions that the DI framework is offering to you. – Darin Dimitrov Sep 12 '13 at 20:21
  • For example if you are writing an ASP.NET MVC application then you could use Ninject.MVC3 which will provide you with a full blown DependencyResolver capable of injecting dependencies in various layers, even in action filters. – Darin Dimitrov Sep 12 '13 at 20:26
  • Thanks for your help. I am just looking for an example that shows something like "without a DI framework like Ninject, X [code example] would not be possible" or "using a DI framework like Ninject makes X [code example] a lot easier/ cleaner than Y [code example]." Do you know what I mean? Just trying to see this in practical terms rather than conceptual terms. – user1477388 Sep 12 '13 at 20:29
0

So what if you want to test your program? With your manual method, the test environment is now dependent on Shuriken() and Sword() being defined.

With a framework like Ninject you can create your application such that the dependencies are introduced when you actually run the application. This means you can pass in mocked data so now your test environment will have no dependencies.

EthanTowne
  • 351
  • 4
  • 14
  • That's absolutely untrue. A DI framework doesn't help at all for unit testing. It has nothing to do with it. You could design a perfectly unit testable system with weak coupling between the layers without any trace of a DI framework. – Darin Dimitrov Sep 12 '13 at 20:11
  • 2
    This Wiki lists testing as a key benefit of DI: http://en.wikipedia.org/wiki/Dependency_injection – ron tornambe Sep 12 '13 at 22:25