【问题标题】:Still need help understanding why Ninject might be better than manual DI仍然需要帮助理解为什么 Ninject 可能比手动 DI 更好
【发布时间】:2011-07-30 18:52:06
【问题描述】:

这是问题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 示例,帮助我了解真正明显的好处。

【问题讨论】:

    标签: c# ioc-container ninject


    【解决方案1】:

    与其他答案不同,Ninject 的主要目的不是让您的代码更具可测试性。依赖注入使您的代码更易于测试!通过在 facotries 中创建所有内容,可以在没有 IoC 容器的情况下使用依赖注入。但可以肯定的是,能够为 集成测试(不要在单元测试中使用 Ninject)轻松替换某些部分是一个很好的副作用。

    像 Ninject 这样的 IoC 容器主要是将您的类整合到一个工作软件中。在小型项目中,这可以使用一些工厂轻松完成。但是随着您的应用程序的增长,工厂变得越来越复杂。想象一个具有各种服务的应用程序,其中一些被重用,另一些是为每次使用而新创建的。一些服务也被多个组件使用。

    如果您使用的是 IoC 容器,您必须只定义一次如何获取服务实例及其生命周期。另一方面,在工厂中,您必须指定如何为每个需要实例的类 获取实例(例如 new MyServiceFactory().CreateInstance())。此外,您必须手动控制生命周期。

    这意味着随着项目的增长,IoC 容器的配置与项目规模一起线性增长。但另一方面,工厂会变得更加指数化,就像在整个应用程序中使用的服务一样(例如用户身份验证)。

    顺便说一句:您的示例不是很好,因为重新绑定不是常见的操作。通常配置只在应用程序启动时完成一次。

    【讨论】:

      【解决方案2】:

      好问题!

      恕我直言,当您要求实例化的代码不知道或不关心实际的实现是什么时,您就可以大获全胜了。这在模拟中最为明显 - 您的模拟框架可以将 Ninject 配置为返回模拟的 Ninja、Sword 和 Samarai,它们以完全不同的方式实现您期望的行为。

      例如,我有一个存储层,它依赖于 IoC 来访问数据存储。对于测试,该数据存储是手动构建的对象集合。对于远程访问,数据存储使用 Web 服务。在本地,它是 SQL。存储库只是从 IoC 请求 IDataStore 并获取配置为提供的任何内容。

      这有帮助吗?

      【讨论】:

        【解决方案3】:

        一个好处来自于测试。

        您可以在生产代码中将 Sword 绑定到 IWeapon,在测试程序集中将 FakeSword 绑定到 IWeapon。当您需要测试依赖于 IWeapon 但您实际上并不想要一把真正的剑的东西时,这很有用。

        例如,您有 IDataContext 和 DataContext,而不是 Sword 和 IWeapon。当您需要连接到数据库时,您的生产代码非常有用。但是对于单元测试,由于各种原因(性能、数据不一致等),您可能不想实际访问数据库。因此,您需要将 FakeDataContext 连接到 IDataContext。现在您已经有了一些控制来模拟用于测试的数据库活动。

        【讨论】:

          【解决方案4】:

          Ninject 与您手动操作相比的主要优势在于,其他人已经为您完成了很多抽象操作。显然,您可以通过向 Ninject 编写类似的代码(用于基于接口类型创建对象的代码)来重现类似的事情,这将允许您将对象构造与对象逻辑分开,但 Ninject(和其他库)已经准备好了为您付出了很多辛勤的工作,所以除非您要添加新的东西,否则为什么要重新创建所有内容?

          您在问题中的比较并不能真正代表我期望使用 Ninject 的方式。您在使用对象的相同方法中进行绑定和重新绑定。我希望容器设置可以在其他地方完成。这允许您更改构造(例如,通过创建模拟对象更容易进行测试),而无需更改实际使用构造对象的代码。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-07
            • 2013-09-07
            • 1970-01-01
            • 2015-03-27
            • 2016-04-28
            • 2012-05-22
            相关资源
            最近更新 更多