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.

4

3 回答 3

3

Darin 的回答涵盖了使用 DI 框架最显着的好处,但这里有一些我发现在使用 DI 容器时很有帮助的东西。假设您有一个具有以下服务依赖项的对象:

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

您的代码可能如下所示:

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

这工作得很好。现在,突然之间,您的要求发生了变化。订单现在需要送货服务:

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

假设您在整个程序中有 10 个不同的地方手动创建订单。如果您自己处理注入,则必须在代码中找到所有 10 个您正在创建订单并修改它们的位置。这样做10次可能是很多工作!

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

然而,使用 DI 容器,一旦你注册了一个绑定,你在所有这 10 个地方的代码如下所示:

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

看看它和以前一样吗?你不必改变任何东西!无论您添加 1 个依赖项还是 100 个依赖项,您解决订单的所有这 10 个位置都不会改变**。因此它可以帮助您避免在需要新依赖项时修改现有代码。

** 情况并非总是如此,但这是一个简化的示例,显示了没人谈论的额外好处之一。

于 2013-09-12T22:08:49.243 回答
1

使用 Ninject 为我提供了哪些我无法通过遵循松散耦合的基本原则来做的事情?

  • 更少的代码行Composition Root
  • 用于处理对象生命周期的标准容器
  • 许多插件用于特定上下文中的注入,例如经典 WebForms、ASP.NET MVC、ASP.NET Web API
  • 自动处理您的 IDIsposable 对象的可能性
  • ...

否则,您应该手动处理的所有事情。话虽如此,DI框架并不重要。它应该很快,并提供您的应用程序所需的特定功能。但是 DI 框架绝对不应该以松散耦合的方式影响您设计代码和应用程​​序中不同层的方式(针对接口和抽象类进行编程以削弱应用程序不同层之间的耦合)。

因此,可以将 DI 框架视为仅干预应用程序的组合根的东西,并且可以将其视为可以在眨眼之间用不同的框架替换甚至手动处理对象生命周期的框架。

例如,您在问题中显示的代码非常糟糕,因为它将您的层与特定的 DI 框架联系起来。那边的这个[Inject]属性就像癌症一样。这意味着您的应用程序代码依赖于特定的 DI 框架。

于 2013-09-12T20:06:03.747 回答
0

那么如果你想测试你的程序呢?使用您的手动方法,测试环境现在取决于定义的 Shuriken() 和 Sword()。

使用像 Ninject 这样的框架,您可以创建应用程序,以便在实际运行应用程序时引入依赖项。这意味着您可以传入模拟数据,因此现在您的测试环境将没有依赖关系。

于 2013-09-12T20:11:18.173 回答