【问题标题】:Why not inject IServiceProvider instead of each individual dependency?为什么不注入 IServiceProvider 而不是每个单独的依赖项?
【发布时间】:2019-08-27 22:05:05
【问题描述】:

我想知道为什么不显式使用 IServiceProvider 来解决依赖关系,而不是单独注入每个依赖项。换句话说,为什么要使用这种方法:

public class A 
{
    private B _b;
    private C _c;
    private D _d;
    private E _e;

    public A(B b, C c, D d, E e)
    {
        _b = b;
        _c = c;
        _d = d;
        _e = e;
    }
}

不是这个:

public class A 
{
    private B _b;
    private C _c;
    private D _d;
    private E _e;

    public A(IServiceProvider sp)
    {
        _b = (b) sp.GetService(typeof(b));
        _c = (c) sp.GetService(typeof(c));
        _d = (d) sp.GetService(typeof(d));
        _e = (e) sp.GetService(typeof(e));
    }
}

请注意,我可能不会为所有类型调用GetService,某些类型可能实际上是可选的(即有时使用,有时不使用)。

第二种方法的优点是,如果 A 的依赖项发生变化,我们不需要在调用 A 的构造函数的每个地方都进行更改,并且我们不需要无论我们在哪里调用构造函数,所有依赖项都已经可用。

MS 似乎在以下文章中建议不要这样做:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2#recommendations 他们提到要避免使用服务定位器模式而不是 DI,但我们这里不是还在使用 DI 吗?无论如何,同样的事情不会在后台发生吗?

【问题讨论】:

  • ...无论我们在哪里调用构造函数... ...那你为什么需要 DI?
  • 使用第二种方法,您可以将整个应用程序依赖项注入到您打算使用它们的任何位置,而不管您实际需要哪些依赖项。这会增加对象创建时间。
  • @MartBroekkamp 如果您在单个控制器中有 10 多个依赖项 - 这是代码味道,告诉您您的控制器做得太多。我会把它分成更小的控制器。或者聚合外观背后的依赖关系。此外,创建服务实例应该既便宜又容易,即构造函数除了分配依赖项之外不应该做任何事情。
  • @mjwills OP,据我所知,服务定位器模式对于处理生命周期没有任何内在意义。正如您已经指出的那样,这会很痛苦。
  • @mjwills 点了,我尝试为 IServiceProvider 方式编写单元测试,并很快意识到这将是多么痛苦。

标签: c# dependency-injection .net-core


【解决方案1】:

有几个原因。 当您使用依赖注入时,您将赋予 DI 容器为您准备依赖项的责任。这些类不应该关心您的依赖项是如何创建的。如果切换到不同的 DI 库,则必须更改所有类中的构造函数。

另一个小问题是,您必须在每个单元测试中为您的服务容器创建一个模拟,这不是一个大问题,但肯定会很烦人。

最后,当你必须将依赖项传递给嵌套类时,你的代码会变得非常奇怪,更不用说你想要继承的任何时候了。

【讨论】:

    【解决方案2】:

    这称为服务定位器模式 -> https://en.wikipedia.org/wiki/Service_locator_pattern

    它有一些优点和缺点(在文章中描述),但是它被广泛视为一种反模式。


    您声明自己正在调用构造函数(我猜是new SomeService(...)),这表明不使用 DI(或仅部分使用)。

    【讨论】:

    • 部分,我想。我们在控制器中使用没有 IServiceProvider 的 DI。我想即使我们注入 IServiceProvider 并从那里获取我们的服务,我们仍在使用 DI,因为我们不需要到处传递依赖项,只有 IServiceProvider 可以通过 DI 框架获取我们的依赖项.我的假设是在后台发生了类似的事情,但我想确实将所有依赖项放在构造函数中更清楚地表达了框架的意图。
    猜你喜欢
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 2011-07-03
    • 2019-10-02
    • 1970-01-01
    • 2011-03-24
    相关资源
    最近更新 更多