MS DI为什么要注册实施

时间:2019-09-28 12:36:48

标签: asp.net-core dependency-injection

从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容器主要是通过Interface来抽象的,因此解决方案是松散耦合的。

我们什至需要注册吗?

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

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

serviceCollection.AddScoped(ICertificateService, CertificateService);

1 个答案:

答案 0 :(得分:2)

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

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

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

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

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

这样,您将注入IEnumerable<MyDep> myDeps,然后使用类似以下内容的方法进行检查:

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

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

您的部分问题是:

  

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

尽管最初并没有多大意义(即可以在需要时实例化类),但该模式确实有助于“构造者诚实”:

  

如果您定义了可以构造和调用的类,但这些类仅在某些全局或基础结构组件到位的情况下才能正常运行,则这些类与它们的客户端不诚实。

参考:Explicit dependencies

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

值得注意的是,这种方法不那么受欢迎的另一个原因是,您在整个应用程序中都绑定了特定的实现-您只是将new关键字移入了容器编排中。 (New is Glue

最后一个问题:

  

下面还有什么区别?

我认为您可能是在这两者之间?

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

我相信第二种方法只是将服务及其实现指定为类型参数的一种方式,而不必使用运行时反射。但这还不够,因为它无法处理类型直到运行时才知道的情况。