了解Ninject的好处

本文关键字:Ninject 了解 | 更新日期: 2023-09-27 18:31:03

我已经看到了这个问题 仍然需要帮助来理解为什么 Ninject 可能比手动 DI 更好,但我仍然对 Ninject 的有用性感到困惑......

我知道这段代码...

class Samurai
{
    readonly IWeapon weapon;
    [Inject]
    public Samurai(IWeapon weapon)
    {
        this.weapon = weapon;
    }
    public void Attack(string target) 
    {
        this.weapon.Hit(target);
    }
}

。将生成以下"动态方法,(基本上)如下所示:"

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

这到底有什么用? 没有 Ninject,我仍然可以这样做(根据 Ninject 文档"手动依赖注入" - 没有 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");
    }
}

使用 Ninject 为我提供了什么,而我不能仅仅遵循松耦合的基本原理来做到这一点? 谢谢你帮助我理解。

了解Ninject的好处

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>();

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

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

使用 Ninject 为我提供了什么,我不能仅仅通过 遵循松耦合的基本原理?

  • Composition Root中的代码行数更少
  • 用于处理对象生存期的标准容器
  • 许多用于在特定上下文中注入的插件,例如经典的WebForms,ASP.NET MVC ASP.NET Web API
  • 可以自动释放您的 IDI 可处理对象

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

因此,将

DI 框架视为仅干预应用程序的复合根,并视为可以在眨眼间用不同的框架替换的框架,甚至可以手动处理对象生存期。

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

那么,

如果你想测试你的程序呢? 使用手动方法,测试环境现在依赖于正在定义的手里剑()和Sword()。

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