上篇文章《在.NET Core 3.0中的WPF中使用IOC图文教程
<https://www.cnblogs.com/yilezhu/p/11099358.html>》中,我们尝试在WPF中应用.NET Core
内置的IOC进行编程,在解析MainWindow的时候我用了GetRequiredService<T>()方法,当时就在想这个
GetRequiredService<T>()方法跟GetService<T>()
到底有什么区别呢,于是乎,谷歌了一把,就发现了一篇文章来介绍他们区别的,于是乎尝试翻译一把,希望对大家有所帮助。文章最后会给出原文链接,以下就是翻译内容:

作者:依乐祝
原文地址:https://www.cnblogs.com/yilezhu/p/11107648.html
<https://www.cnblogs.com/yilezhu/p/11107648.html>

本文将介绍Microsoft.Extensions.DependencyInjection中提供的默认/内置ASP.NET Core DI容器的方法
GetService<T>()和GetRequiredService<T>()方法。我将描述它们之间的差异以及您应该使用哪种方法。

如果服务不存在则GetService()返回null,GetRequiredService()而是抛出异常。如果您正在使用第三方容器,请尽可能使用
GetRequiredService- 如果发生异常,第三方容器可能就会根据异常信息提供相应的诊断信息,以便您可以找出未注册预期服务的原因。

容器的核心 - IServiceProvider接口

ASP.NET Core依赖注入抽象的核心是IServiceProvider接口。该接口实际上是System命名空间中基类库的一部分。接口本身很简单:
public interface IServiceProvider { object GetService(Type serviceType); }
一旦您使用DI容器(使用IServiceCollection)注册了所有类,几乎所有DI容器需要做的就是允许您使用GetService()查找对象的实例。

当然,您通常根本不应该直接在代码中使用IServiceProvider。相反,您应该使用标准的构造函数注入,并让框架来承载并在幕后使用
IServiceProvider。

直接使用IServiceProvider是服务定位器模式的一个示例。这通常被认为是反模式
<http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/>,因为它隐藏了类的依赖关系。

然而,有些时候你没有选择的余地。例如,如果您试图将服务注入到属性
<https://andrewlock.net/injecting-services-into-validationattributes-in-asp-net-core/>
,或者在配置DI容器时使用“转发”类型 <http://disq.us/p/1cedzyz>,则需要直接使用IServiceProvider。

比较GetService ()和GetRequiredService ()

鉴于我们不再使用.NET 1.0,如果你想从IServiceProvider中检索服务,你可能使用了通用的泛型GetService<T>()扩展方法,而不是
GetService(Type)接口方法。但是你可能也注意到了类似的GetRequiredService<T>()扩展方法 -
问题是,它们之间有什么区别呢,您应该使用哪种方法?

在我们研究任何代码之前,让我们先讨论一下这些方法的预期行为。首先,从GetService()方法的文档开始:

GetService()返回一个serviceType类型的服务对象。如果返回的是一个没有类型的服务对象serviceType则返回null。

与GetRequiredService()的文档内容进行对比:

GetRequiredService()返回一个serviceType类型的服务对象。如果没有serviceType类型的服务,则抛出一个
InvalidOperationException异常。

因此,当请求的实例serviceType可用时,两种方法的行为都相同。不同之处在于serviceType未注册时的行为:

* GetService- 如果服务未注册,则返回null
* GetRequiredService- 如果服务未注册,则抛出一个Exception异常。
现在我们已经清楚了,让我们看看一些代码。

在ServiceProviderServiceExtensions班上
Microsoft.Extensions.DependencyInjection.Abstractions库中
<https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection.Abstractions>
同时实现了通用版GetService<T>()和GetRequiredService<T>()方法,如下所示:

我已经从本文的代码中删除了一些前提条件检查; 如果你想看到完整的代码,请在GitHub上查看
<https://github.com/aspnet/DependencyInjection/blob/94b9cc9ace032f838e068702cc70ce57cc883bc7/src/DI.Abstractions/ServiceProviderServiceExtensions.cs>

public static class ServiceProviderServiceExtensions { public static T
GetService<T>(this IServiceProvider provider) { return
(T)provider.GetService(typeof(T)); } public static T GetRequiredService<T>(this
IServiceProvider provider) { return (T)provider.GetRequiredService(typeof(T));
} }
这两种方法实际上都是相同的 - 通用扩展方法委托给非泛型版本的GetService()和GetRequiredService()
。它们只是一种便利,因此您在自己的代码中不需要使用更多的typeof()和类型转换。

非泛型版本的GetService()是IServiceProvider接口的一部分,但非泛型GetRequiredService()实现是同一类中的扩展方法:
public static class ServiceProviderServiceExtensions { public static object
GetRequiredService(this IServiceProvider provider, Type serviceType) { var
requiredServiceSupportingProvider = provider as ISupportRequiredService; if
(requiredServiceSupportingProvider != null) { return
requiredServiceSupportingProvider.GetRequiredService(serviceType); } var
service = provider.GetService(serviceType); if (service == null) { throw new
InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType)); }
return service; } }
该方法的第一步是检查提供的IServiceProvider 是否也实现了ISupportRequiredService。此接口提供底层的非泛型
GetRequiredService实现,因此如果服务提供者实现它,GetRequiredService()则可以直接调用。

ASP.NET Core内置的DI容器并没有实现ISupportRequiredService- 只有第三方容器实现了GetRequiredService()


如果IServiceProvider没有实现ISupportRequiredService,则执行所需的异常抛出行为,如您所料:GetService()
调用,如果返回null则抛出异常。

那你应该使用哪种方法?

正如我之前所说,理想情况下,两者都可以!

在您自己的代码使用ISeviceProvider通常是你正在使用服务定位器反模式
<http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/>的一个标志,所以一般应避免使用
ISeviceProvider。但是,如果由于设计限制而需要(例如,您不能在属性中使用DI
<https://andrewlock.net/injecting-services-into-validationattributes-in-asp-net-core/>
),或者作为DI容器配置本身的一部分 <http://disq.us/p/1cedzyz>的情况下,您应该使用哪一种呢?

基于GitHub <https://github.com/aspnet/DependencyInjection/issues/378>中要求添加
GetRequiredService()的原始问题
<https://github.com/aspnet/DependencyInjection/issues/378>,以及Jeremy D. Miller
<https://jeremydmiller.com/>先前提出的问题
<https://github.com/aspnet/DependencyInjection/issues/238> ,我认为几乎所有情况下的规则是:

使用 GetRequiredService()

* 减少重复。如果服务不可用,则使用GetRequiredService()会立即抛出异常。如果您使用GetService()
,那么您需要在调用代码中检查是否为null,并且通常需要抛出异常。那个空检查代码需要在任何地方重复。
* 失败很快。如果您在使用GetService()时忘记检查是否为null,那么稍后您的程序可能会以NullReferenceException
结束。找出导致异常的原因总是比显式的告诉你的InvalidOperationException更困难,需要做更多的工作。
* 允许对第三方容器进行高级诊断。StructureMap和其他一些第三方容器的一大好处是,它们能够提供详细的异常消息,说明为什么找不到服务。如果您正在使用
GetRequiredService(),则第三方容器本身会生成异常,因此可以提供其他特定于容器的信息。只返回null(带GetService()
)不会给你进一步的详细的信息。这是引入GetRequiredService()的主要原因
<https://github.com/aspnet/DependencyInjection/issues/378>。
当然,我已经看到了一些反对GetRequiredService()`的观点,但我认为其中任何一个都不会受到审查:

* “我没有使用第三方容器”。如果您正在使用内置容器(未实现ISupportRequiredService),那么您将无法通过使用任何其他诊断获益
GetRequiredService()。但是,我认为前两个优势仍然存在,并使GetRequiredService
值得使用。此外,如果您以后添加第三方容器,您已经在使用最佳实践了。
* “我有可选服务,有时只在DI容器中注册。” 。这可能是使用GetService()
唯一有效的理由。如果您的代码只有在注册了给定服务时才能运行,那么您可能需要使用GetService()。但是,如果GetService()
返回NULL,我也看到它在使用回退服务时使用。在我看来,这很少是应用程序代码的好模式。回退的编排应该是DI容器配置的一部分,而不是使用服务的位置。
所以,现在你有了 - GetService()与GetRequiredService()
之间的对比了。在我进一步挖掘它之前,当我选择一个而不是另一个时,我有点武断,但现在我会确保我总是理所当然的使用GetRequiredService()。

摘要

GetService()是IServiceProvider上的唯一方法,ISeviceProvider
是ASP.NET核心DI抽象中的中央接口。第三方容器还可以实现可选接口ISupportRequiredService,该接口提供
GetRequiredService()方法。当请求的类型serviceType可用时,这些方法的行为相同。如果服务不可用(即它没有注册),则
GetService()返回null,而GetRequiredService()抛出一个InvalidOperationException。

GetRequiredService()相对于GetService()
的主要好处是当服务不可用时,它允许第三方容器提供额外的诊断信息。因此,在使用第三方容器时最好使用GetRequiredService()
。就个人而言,我会在任何地方使用它,即使我只使用内置的DI容器。

原英文链接:
https://andrewlock.net/the-difference-between-getservice-and-getrquiredservice-in-asp-net-core/

<https://andrewlock.net/the-difference-between-getservice-and-getrquiredservice-in-asp-net-core/>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信