Dependency injection 构造函数中的依赖项注入容器

Dependency injection 构造函数中的依赖项注入容器,dependency-injection,Dependency Injection,为什么在构造函数中放置容器如此糟糕?例如,您希望在另一个类(C)的构造函数中解析类B,因为您需要将该类(B)与已解析的依赖项一起使用(您开始以希望的方式使用类C,就像它是B一样,但与已解析的依赖项一起使用) 为什么在构造函数中放置容器如此糟糕 我想您的意思是将容器作为构造函数参数传递。这实际上是服务定位器模式的一种变体,在本文中,它被认为是一种反模式。您可能不想这样做有几个原因 首先,类的用户只知道该类需要一个容器来解析其依赖项。这些信息量等于没有任何信息,因为您仍然不知道类将依赖于什么。是否要

为什么在构造函数中放置容器如此糟糕?例如,您希望在另一个类(C)的构造函数中解析类B,因为您需要将该类(B)与已解析的依赖项一起使用(您开始以希望的方式使用类C,就像它是B一样,但与已解析的依赖项一起使用)

为什么在构造函数中放置容器如此糟糕

我想您的意思是将容器作为构造函数参数传递。这实际上是服务定位器模式的一种变体,在本文中,它被认为是一种反模式。您可能不想这样做有几个原因

首先,类的用户只知道该类需要一个容器来解析其依赖项。这些信息量等于没有任何信息,因为您仍然不知道类将依赖于什么。是否要为类编写单元测试?您必须查看类内部并查看它正在解析哪些类型,模拟它们并为每个测试初始化容器。这也意味着对某些代码的更改将允许它编译,但可能会破坏某些测试:例如,当新代码依赖于尚未在容器中注册的类时,就是这种情况

使用服务定位器时常见的第二个影响是,在请求依赖项时,您永远无法确保在运行时不会出现异常。每个班级注册正确吗?虽然有些容器提供了检查每个接口是否已注册的可能性,但这并不意味着它已注册为正确的类型。例如,一个类型可能会在两个不同的实现中注册两次,并且很难注意到是否有任何代码段可以调用容器

一个更好的解决方案是。还解释了为什么服务定位器可能不是一个好主意


根据新的发展情况进行编辑:

显然,您使用的是第三方库,它依赖于您的类具有默认构造函数。让我们假设您没有办法影响类的实例化,您必须让这个框架完成它的工作。请注意,这可能是一个很大的假设,请调查第三方库,以了解是否有可能先这样做。乍一看,像ASP.NET WebForms和WCF这样的框架并没有给你很多机会,但是有一些方法可以减轻这些情况下的痛苦


我只是想在构造函数中创建容器,添加 分别依赖于容器并解析对象 只需创建依赖项对象的实例和 使用它创建从属对象

我可能遗漏了一些东西,但是为什么需要在构造函数中注册依赖项呢?您不能在构造函数中解析它,但在其他地方注册它吗?这仍然是一个服务定位器,但至少你做得不对

为什么在构造函数中这样做是个坏主意而在其他地方这样做 好吗

在一个地方以外的任何地方这样做都是一个坏主意。你为什么要把你的集装箱登记分散到各地?如果您确实觉得有必要决定在运行时使用什么接口实现,请使用类似于工厂的东西

那么,为什么不好呢

  • 客户机类同时依赖于实现和接口,这并不比在构造函数中更新具体类更好
  • 客户机类现在也依赖于容器,并且出现了服务定位器的问题(见上文),这使得这种方法比更新具体类更糟糕
正如@Steven所说,您将失去依赖注入的所有优势。真正潜在的问题是:为什么你绝对想在这里做DI?您希望使用该方法的哪些优点?根据答案,可能有几种解决方案。我脑海中有两个例子:

解决方案1:丢失由第三方库实例化的类的DI

解决方案2:使用注射+服务定位器的组合。在这种情况下,两个错误可以构成一个正确

public class MyClass
{
    public MyClass()
        : this(Container.Resolve<IDependency>())
    {
    }

    public MyClass(IDependency dep)
    {
    }
}
公共类MyClass
{
公共MyClass()
:此(Container.Resolve())
{
}
公共MyClass(独立事务部)
{
}
}

在这种情况下,您没有在构造函数中使用非本地依赖项,因为它是由服务定位器解析的,因此您对实现没有依赖项。

我的意思是在构造函数中创建容器,将相应的依赖项添加到容器并解析对象,这可以通过简单地创建依赖对象的实例并使用它来创建依赖对象来完成。在这种情况下,这很重要,因为存在一个链依赖关系,手动创建作为链一部分的每个对象并将其作为构造函数参数传递给每个连续的依赖对象可能会很繁琐。至于服务定位器——在本例中,这是一个已知的反模式,但这不是我的问题。在每个类中创建和配置一个容器简直是疯了。这迫使类再次完全控制其依赖项,这与在构造函数中更新依赖项完全相同。您将失去依赖注入的所有好处,并使事情比“按旧方式”更复杂,因为更新将比配置为您创建这些实例的容器更容易理解。“有一个链依赖项,手动创建链中的每个对象,并将其作为构造函数参数传递“。请开始一个新问题,并更彻底地解释这一点,并解释为什么您不能让构造函数注入工作。如果您认为不能使用构造函数注入,我希望您的设计中会有缺陷。能够帮助你吗