代码之家  ›  专栏  ›  技术社区  ›  Ted

DI框架:如何避免在不使用服务定位器的情况下(特别是使用Ninject)连续地向上传递注入的依赖项。

  •  14
  • Ted  · 技术社区  · 15 年前

    我需要更多的帮助来“了解”Ninject这样的DI框架是如何超越基础的。

    取9个样本:

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

    如果没有DI框架(即上面的[inject]引用),引用类将类似于:

    class Program {
       public static void Main() { 
        Samurai warrior1 = new Samurai(new Shuriken());
        Samurai warrior2 = new Samurai(new Sword());
        warrior1.Attack("the evildoers");
        warrior2.Attack("the evildoers");
      }
    }
    

    …你正在更新一切。是的,你已经消除了对武士的依赖,但是现在你已经有了一个更进一步的依赖。简单。

    有了Ninject,您可以通过以下方式摆脱所有更新:

    class Program {
      public static void Main() {
        IKernel kernel = new StandardKernel(new WarriorModule());
        Samurai warrior = kernel.Get<Samurai>();
        warrior.Attack("the evildoers");
      }
    }
    

    但是,这是我的困惑所在:如果不制作某种服务定位器来有效地更新适用的内核和模块(即ioc.typeresolver.get<>()),什么是a)不必到处更新内核的最佳方法(服务定位器引用无处不在?)和b)更重要的是,当你有一个很大的长链依赖于他们自己的依赖性时,你会把它带到一个极端,一路向上传递注入,我确信这是一个严重的反模式(一个朋友称之为“热土豆依赖性注入”反模式)。

    换句话说,我认为DI框架魔力的一部分是,您不必一直在链的上游插入依赖项(即,您的第一个引用在其构造函数中包含10个参数,在链的更远处之前,这些参数都与任何事情无关),在哪里? 魔术 或者解决我的困惑,这样依赖关系就不会不断地被引用到链上,或者服务定位器引用散布到各处。

    对我来说,更糟糕的是,如果使用DI框架,处理一个引用类需要一个IList的场景的最佳方法是什么?通常将该IList放入构造函数(即,新的引用类(MyList)),因为除了字符串数据库连接字符串这样的简单情况外,它不会飞起来。只需创建一个属性并在更新它之后设置它/DI框架服务定位?即。

    var referencedClass = IoC.Get<IReferencedClass>();
    referencedClass.MyList = myList;
    

    总之,我认为这是一个我可能会感到尴尬的帖子后,我得到它,但现在,我已经击中我的头太多次靠墙,试图确定最好的方法。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Eric King    15 年前

    至于“烫手山芋”的依赖性问题,这不必发生。依赖注入框架为您处理这个问题。

    例如,如果Class1依赖于Class2,而Class2依赖于Class3,则 需要向Class1中注入Class3,以适应Class2的依赖关系。当您请求Class1时,内核将为您遍历依赖链,并自动解析下游依赖项(只要所有正在运行的类都已在内核中注册)。

    第1类取决于第2类取决于第3类

    Class1构造函数根本不需要提到Class3。

    至于第二个问题,如何或是否解决这一问题取决于框架。有了Ninject,我想你可以使用 Bind().To().WithConstructorArgument() 为构造函数提供新列表项的语法。