仅在应用程序启动时使用 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 个类进入每个构造函数,不是吗?
所以,如果我有一个复杂的依赖关系图,我只能使用依赖关系容器?
有人可以给我一个例子,如果你使用依赖容器,它只是在应用程序的根目录下的样子吗?
如果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 容器来执行此操作,但如果你愿意,可以使用一个。