IoC.Resolve与构造函数注入

Omu*_*Omu 44 .net ioc-container inversion-of-control

我听到很多人说使用IoC.Resolve()是一种不好的做法,但我从来没有听说过一个很好的理由(如果它只是测试而不是你可以嘲笑容器,那么你已经完成了).

现在使用Resolve而不是Constructor Injection的优点是你不需要在构造函数中创建具有5个参数的类,并且无论何时你要创建该类的实例,你都不需要提供它.什么

Bry*_*tts 49

IoC.Resolve<>服务定位器模式的一个示例.该模式强加了一些构造函数注入没有的限制:

  • 由于静态调用,对象不能具有比应用程序域更细粒度的上下文
  • 对象决定要解析的依赖项版本.某个类的所有实例都将获得相同的依赖项配置.
  • 将代码耦合到容器的诱惑很高,例如,不是创建一个有意图的工厂.
  • 单元测试需要容器配置,其中可以仅创建和使用类.(由于上面的第二个问题,当你想测试同一个类的多个配置时,这尤其麻烦.)
  • 无法从其公共API推断应用程序的结构.(构造函数的参数是一个很好的事情.他们不应该感到需要解决的一个问题.)

在我看来,这些限制将服务定位器模式放在大泥球和依赖注入之间的中间位置:如果必须使用它,则很有用,但到目前为止并非最佳选择.

  • 一切都很好,除了一个错字.它应该是:`IoC.Resolve <>`是服务定位器**反**模式的​​一个例子. (13认同)
  • 依赖版本允许您具有相同合同(接口)的多个实现.这通常使用字符串名称或类似的效果来完成.在上面的示例中,实时电子邮件配置将在`IEmailService`下注册(表明它是该合同的默认实现).本地配置将在`IEmailService("Local")`下注册,表明必须通过名称引用它.使用构造函数注入时,对象不知道它获得了哪个版本; 使用服务定位器,它必须决定它获得的版本. (5认同)
  • +1表示Resolve实际上是服务定位器模式,我以前从未考虑过. (3认同)
  • 细粒度上下文意味着您在同一应用程序中以不同方式配置相同的合同(接口).例如,您可能有一个带有两个实现的`IEmailService`:一个发送实时电子邮件,另一个发送只发送到本地服务器.如果类'Foo`通过`IoC.Resolve <>`请求`IEmailService`,它只能选择其中一个 - 关于它将被使用的上下文的任何内容都被考虑到决定`IEmailService`配置到解决.`Foo`的所有实例都将获得与`IEmailService`完全相同的配置. (3认同)

Krz*_*mic 26

如果创建具有5个依赖项的类,则除IoC.Resolve之外还有其他问题.

拉动依赖项(而不是通过构造函数推送它们)完全忽略了使用IoC框架的重点.您想要反转依赖项.没有你的类依赖于IoC框架,反之亦然.

如果在某些情况下不需要所有依赖项,那么可能应该拆分类,或者通过使它们成为属性依赖项使某些依赖项成为可选项.


您的类取决于容器.除非你提供一个,否则它们将无法工作.无论是真的还是假的都无所谓.它们通过静态依赖性固有地绑定到容器.这会给你额外的工作带来任何你的课程.任何时候你想使用你的类,你需要用它们拖动容器.没有好处!服务定位器只是一切的全局包,这可能违背了面向对象编程的所有原则.

  • 当您违反SRP时,+1构造函数注入会让您感到非常明显:) (8认同)
  • 您的类取决于容器.除非你提供一个,否则它们将无法工作.无论是真的还是假的都无所谓.它们通过静态依赖性固有地绑定到容器. (3认同)
  • 这与更改容器实现无关.它与调用某个对象(在这种情况下为IoC.Resolve())的事实有关*不是*IoC!你问的是你的依赖,而不是让某些东西给你.如果使用得当,您不需要在容器周围创建自己的"抽象",因为您的代码根本不知道它存在! (3认同)
  • @Chris我认为服务定位器应该尽可能地避免......这是一个用来代替实际理解DI的拐杖,并且不会像DI那样使代码更好.虽然我同意在某些情况下对容器的引用是有用的,但我认为它们很少且很远,并且大多数人提出这类问题并不是他们实际需要这样做的情况.在这种情况下,强烈建议他们在完全理解DI之前不要引用容器. (3认同)
  • @Omu,不是真的.通过使用SL,您将获得贷款,您必须在以后偿还.你可能会认为你正在快速启动代码,但实际上它就像在长时间运行之前没有系鞋带 - 在任何时候你都会发现自己面朝下.SL是其中一个可能在开始时看起来很吸引人的想法,但从长远来看,它们会产生比他们解决的问题更多的问题. (3认同)

Gra*_*lin 7

Ioc.Resolve本质上是服务定位器模式.它有它的位置,但并不理想.从体系结构的角度来看,构造函数注入是首选,因为依赖性更明确,而SL隐藏了类中的依赖项.这降低了可测试性,并使该过程比需要的更复杂.

如果可以,我建议你阅读我最近关于减少代码耦合技术的系列文章,其中包括SL,DI和IoC.