我已经看到了这个问题Still need help understanding why Ninject might be better than manual 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文档“手工依赖注入” - 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");
}
}
使用Ninject为我提供的是什么,我只能遵循松散耦合的基本原则而无法做到?谢谢你帮助我理解。
答案 0 :(得分:2)
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个。因此,它可以帮助您不必修改现有代码,因为需要新的依赖项。
**情况并非总是如此,但这是一个简单的例子,展示了没人谈过的其他好处之一。
答案 1 :(得分:1)
使用Ninject为我提供的是我不能做的事情 遵循松散耦合的基本原则?
Composition Root
您应该手动处理的所有事情。话虽如此,DI框架并不重要。它应该很快,并提供您的应用程序所需的特定功能。但DI框架绝对不会以松散耦合的方式影响应用程序设计代码和应用程序中不同层的方式(针对接口和抽象类进行编程以削弱应用程序不同层之间的耦合)。 / p>
因此,将DI框架视为仅在应用程序的组合根中进行干预的内容,以及可以在一眨眼间用不同的框架替换甚至手动处理对象生命周期的框架。
例如,您在问题中显示的代码非常糟糕,因为它将您的图层绑定到特定的DI框架。这个[Inject]
属性就像癌症一样。这意味着您的应用程序代码依赖于特定的DI框架。
答案 2 :(得分:0)
那么如果你想测试你的程序怎么办?使用手动方法,测试环境现在依赖于定义的Shuriken()和Sword()。
使用像Ninject这样的框架,您可以创建应用程序,以便在实际运行应用程序时引入依赖项。这意味着您可以传入模拟数据,因此现在您的测试环境将没有依赖项。