c# - 仍然需要帮助理解为什么 Ninject 可能比手动 DI 更好

标签 c# ioc-container ninject

这是对问题 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/

相关文章:

asp.net - 未定义无参数构造函数对象

c# - 达到 DateTime 后执行方法的最有效方法

c# - 从 VideoPlayer 获取当前帧纹理

c# - (自动)依赖注入(inject)绑定(bind)机制

c# - 没有服务定位器的领域事件

c# - 由于 DI 容器绑定(bind)要求,如何避免 BAL 依赖于 DAL?

c# - 仅删除特定区域中的空间

c# - CSS字体打印问题

generics - 使用 Unity,如何使用通用接口(interface)自动注册通用类而不向其注册每种类型

dependency-injection - IoC 上下文中基于代码的注册与设计时注册