这是对问题 Why do I need an IoC container as opposed to straightforward DI code? 的扩展
我一直在学习 Ninject 并提出了以下示例,该示例通过手动执行 DI 的方式和 Ninject 执行 DI 的方式:
class Program
{
static void Main(string[] args)
{
NinjectWay();
ManualWay();
Console.ReadKey();
}
private static void ManualWay()
{
Console.WriteLine("ManualWay***********************");
IWeapon sword = new Sword();
Samurai samurai = new Samurai(sword);
Console.WriteLine(samurai.Attack("ManualWay..."));
// change weapon
IWeapon dagger = new Dagger();
samurai.Weapon = dagger;
Console.WriteLine(samurai.Attack("ManualWay..."));
IWeapon weapon = new Shuriken();
IWarrior ninja = new Ninja(weapon);
Console.WriteLine("Manual way.. inject shuriken when a ninja. " + ninja.Weapon.Name);
IWarrior ninja2 = new Ninja(weapon);
}
private static void NinjectWay()
{
Console.WriteLine("NinjectWay***********************");
IKernel kernel = new StandardKernel();
kernel.Bind<IWeapon>().To<Sword>();
var samurai = kernel.Get<Samurai>();
Console.WriteLine(samurai.Attack("NinjectWay..."));
kernel.Rebind<IWeapon>().To<Dagger>();
samurai = kernel.Get<Samurai>();
Console.WriteLine(samurai.Attack("NinjectWay..."));
kernel.Bind<IWeapon>().To<Shuriken>().WhenInjectedInto<Ninja>();
var ninja = kernel.Get<Ninja>();
ninja.OffHandWeapon = new ShortSword();
Console.WriteLine("Conditional Injection..."+ninja.Weapon.Name);
Console.WriteLine("Conditional Injection: OffhandWeapon = " + ninja.OffHandWeapon.Name);
var ninja2 = kernel.Get<Ninja>();
Console.WriteLine("Conditional Injection..." + ninja2.Weapon.Name);
Console.WriteLine("Conditional Injection: OffhandWeapon = " + ninja2.OffHandWeapon.Name);
Console.WriteLine("");
}
}
我听说当项目规模扩大时会带来好处,但我没有亲眼看到。帮助我更好地理解这一点。在 C#/Ninject 中提供更多示例,帮助我了解优势真正显现的地方。
最佳答案
与其他答案不同,Ninject 的主要目的不是让您的代码更易于测试。依赖注入(inject)使您的代码更具可测试性!通过在工厂中创建所有内容,可以在没有 IoC 容器的情况下使用依赖注入(inject)。但是可以肯定的是,能够为集成测试(不要在单元测试中使用 Ninject)轻松更换一些部件是一个很好的副作用。
像 Ninject 这样的 IoC 容器主要是将你的类放在一个工作软件中。在小型项目中,这可以使用一些工厂轻松完成。但是随着应用程序的增长,工厂会变得越来越复杂。想象一个具有各种服务的应用程序,其中一些服务被重用,其他服务是为每次使用而新创建的。一些服务还被多个组件使用。
如果您使用的是 IoC 容器,则必须定义exactly once 如何获取服务实例及其生命周期。另一方面,在工厂中,您必须指定如何为需要实例的每个类获取实例(例如,new MyServiceFactory().CreateInstance())。此外,您必须手动控制生命周期。
这意味着随着项目的增长,IoC 容器的配置与项目规模一起线性增长。但另一方面,随着整个应用程序中使用的服务(例如用户身份验证),工厂变得更加指数化。
顺便说一句:您的示例不是很好,因为重新绑定(bind)不是常见操作。通常配置只在应用程序启动时完成一次。
关于c# - 仍然需要帮助理解为什么 Ninject 可能比手动 DI 更好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5566180/