仅在应用程序启动时使用 DI 容器

本文关键字:DI 容器 应用程序 启动 | 更新日期: 2023-09-27 18:36:25

通常,我会在 C# 中使用依赖注入容器 (unity),如以下示例所示:

class SomeClass
{
    private readonly ILogger _logger;
    public SomeClass()
    {
        _logger = DependencyContainer.Resolve<ILogger>();
    }
    public void DoSomething()
    {
        var someOtherClass = DependencyContainer.Resolve<...>();
        someOtherClass().whatElseEver();
    }
}

昨天,我读了一些关于使用 di 容器正确依赖注入的文章。在此之后,我知道我的例子是完全糟糕的。这不是依赖注入,这只是一个类似于服务定位器的东西。

好的,如何解决这个问题?我认为使用构造函数注入可以轻松解决此问题:

class SomeClass
{
    private readonly ILogger _logger;
    private readonly ISomeOtherClass _someOtherClass;
    public SomeClass(ILogger logger, ISomeOtherClass someOtherClass)
    {
        _logger = logger;
        _someOtherClass = someOtherClass;
    }
    public void DoSomething()
    {
        _someOtherClass().whatElseEver();
    }
}

现在我有了依赖注入原则的正确实现。但是如何连接所有这些依赖项呢?我有一个调用者类,它解决了类"SomeClass"的所有必需的规范:

class SomeClassCaller
{
    public void DoSomething()
    {
        var logger = DependencyContainer.Resolve<ILogger>();
        var someOtherClass = DependencyContainer.Resolve<...>();
        var someClass = new SomeClass(logger, someOtherClass);
        someClass.DoSomething();
    }
}

但是此示例仍然使用依赖项容器作为服务定位器,这很糟糕。在几乎所有关于此的文章中,我都读到,依赖容器应该只在应用程序根/入口点使用,这是正确的吗?

这意味着,任何类都不应该能够使用"服务定位器"(如记录器)动态解析某些依赖项。我必须通过构造函数将 ILogger 注入到几乎每个类中,以避免这个问题,对吗?这种方式感觉真的很糟糕,如果我让 ILogger 通过 10 个类进入每个构造函数,不是吗?

所以,如果我有一个复杂的依赖关系图,我只能使用依赖关系容器?

有人可以给我一个例子,如果你使用依赖容器,它只是在应用程序的根目录下的样子吗?

仅在应用程序启动时使用 DI 容器

如果SomeClassCaller需要SomeClass,请注入它:

public class SomeClassCaller
{
    private readonly SomeClass someClass;
    public SomeClassCaller(SomeClass someClass)
    {
        this.someClass = someClass;
    }
    public void DoSomething()
    {
        this.someClass.DoSomething();
    }
}

这是具体依赖项的一个示例。不过,通常情况下,您可以让SomeClass实现一个接口,然后将该接口注入SomeClassCaller而不是具体的类中。

在合成根中,您可以连接对象图:

var scc = new SomeClassCaller(
    new SomeClass(
        new MyLogger(),
        new SomeOtherClass()));

你不需要 DI 容器来执行此操作,但如果你愿意,可以使用一个。