首页 > 解决方案 > MS DI 为什么要注册实施

问题描述

从 MS DI 阅读此文档: https ://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0

渴望了解为什么我们需要这些选项:

Add{LIFETIME}<{IMPLEMENTATION}>()
Example:
services.AddScoped<MyDep>();

Add{LIFETIME}(new {IMPLEMENTATION})
Examples:
services.AddScoped(new MyDep());
services.AddScoped(new MyDep("A string!"));

鉴于这些新类没有接口实现,它通过上述操作提供了什么?DI 容器主要通过接口抽象,因此解决方案是松散耦合的。

我们甚至需要注册这个。

下面还有什么区别吗?我认为第一个就足够了:

serviceCollection.AddScoped(typeof(ICertificateService), typeof(CertificateService));

serviceCollection.AddScoped(ICertificateService, CertificateService);

标签: asp.net-coredependency-injection

解决方案


在您引用的示例中,图表显示这两个用例是唯一提供所有三个特征(自动对象处置、多个实现和传递参数)的用例。这样做有几个原因。

如果实现实现IDisposable,容器将自动处理处置(不需要using块) - 第一个特征。

如果您需要多个实现(两个不同的类实现相同的接口,或者一个类的实例接受构造函数参数而另一个实例不接受),您可以通过这种方式添加它们 - 第二个特征。

如果需要,构造函数参数也可以来自容器,因为IServiceProvider是传入的 - 第三个特征。

列出了另外两个可以接受参数的重载;一个有类型参数但没有IServiceProvider传入 - 它没有自动处理;另一个也没有 - 它没有自动处置或多个实现。

这样,您将注入一个IEnumerable<MyDep> myDeps,然后使用以下内容对其进行检查:

var myDep = myDeps.Single(x => x.ReadOnlyProperty == "A string!");

实际上,如果其中一个实例具有另一个可以由容器同时处理的范围服务(如 aDbContext或),这将很有用。UserManager

您的部分问题是:

鉴于这些新类没有接口实现,它通过上述操作提供了什么?

虽然最初没有多大意义(即类可能只在需要时被实例化),但该模式确实有助于“构造函数诚实”:

如果您定义了可以构造和调用的类,但只有在某些全局或基础设施组件到位时才能正常运行,那么这些类对它们的客户是不诚实的。

参考:显式依赖

另一方面,如果方法MyDep不是虚拟的,它们将很难在模拟单元测试中被覆盖(这就是为什么这种模式不像注入接口那样常见,在模拟中所有东西都可以被覆盖)。

同样值得注意的是,这种方法不那么受欢迎的另一个原因是您在整个应用程序中都与特定实现相关联 - 您只是将new关键字向上移动到容器编排中。(新是胶水

对于你的最后一个问题:

下面还有什么区别吗?

我想也许你的意思是在这两者之间?

serviceCollection.AddScoped(typeof(ICertificateService), typeof(CertificateService));
serviceCollection.AddScoped<ICertificateService, CertificateService>();

I believe the second is just a way to specify the service and its implementation as type parameters instead of having to use runtime reflection. But it wouldn't be enough, since it wouldn't handle situations where the type isn't known until runtime.


推荐阅读