上篇文章《在.NET Core 3.0中的WPF中使用IOC图文教程》中,咱们尝试在WPF中应用.NET Core
内置的IOC进行编程,在解析MainWindow
的时候我用了GetRequiredService<T>()
方法,当时就在想这个GetRequiredService<T>()
方法跟GetService<T>()
到底有什么区别呢,因而乎,谷歌了一把,就发现了一篇文章来介绍他们区别的,因而乎尝试翻译一把,但愿对你们有所帮助。文章最后会给出原文连接,如下就是翻译内容:html
做者:依乐祝
原文地址:http://www.javashuo.com/article/p-vrbcckrr-kg.htmlgit
本文将介绍Microsoft.Extensions.DependencyInjection
中提供的默认/内置ASP.NET Core DI容器的方法GetService<T>()
和GetRequiredService<T>()
方法。我将描述它们之间的差别以及您应该使用哪一种方法。github
若是服务不存在则
GetService()
返回null
,GetRequiredService()
而是抛出异常。若是您正在使用第三方容器,请尽量使用GetRequiredService
- 若是发生异常,第三方容器可能就会根据异常信息提供相应的诊断信息,以便您能够找出未注册预期服务的缘由。编程
ASP.NET Core依赖注入抽象的核心是IServiceProvider
接口。该接口其实是System
命名空间中基类库的一部分。接口自己很简单:框架
public interface IServiceProvider { object GetService(Type serviceType); }
一旦您使用DI容器(使用IServiceCollection
)注册了全部类,几乎全部DI容器须要作的就是容许您使用GetService()
查找对象的实例。ide
固然,您一般根本不该该直接在代码中使用IServiceProvider
。相反,您应该使用标准的构造函数注入,并让框架来承载并在幕后使用IServiceProvider
。函数
直接使用
IServiceProvider
是服务定位器模式的一个示例。这一般被认为是反模式,由于它隐藏了类的依赖关系。ui
然而,有些时候你没有选择的余地。例如,若是您试图将服务注入到属性,或者在配置DI容器时使用“转发”类型,则须要直接使用IServiceProvider
。this
鉴于咱们再也不使用.NET 1.0,若是你想从IServiceProvider
中检索服务,你可能使用了通用的泛型GetService<T>()
扩展方法,而不是GetService(Type)
接口方法。可是你可能也注意到了相似的GetRequiredService<T>()
扩展方法 - 问题是,它们之间有什么区别呢,您应该使用哪一种方法?.net
在咱们研究任何代码以前,让咱们先讨论一下这些方法的预期行为。首先,从GetService()
方法的文档开始:
GetService()
返回一个serviceType
类型的服务对象。若是返回的是一个没有类型的服务对象serviceType
则返回null
。
与GetRequiredService()
的文档内容进行对比:
GetRequiredService()
返回一个serviceType
类型的服务对象。若是没有serviceType
类型的服务,则抛出一个InvalidOperationException
异常。
所以,当请求的实例serviceType
可用时,两种方法的行为都相同。不一样之处在于serviceType
未注册时的行为:
GetService
- 若是服务未注册,则返回null
GetRequiredService
- 若是服务未注册,则抛出一个Exception
异常。如今咱们已经清楚了,让咱们看看一些代码。
在ServiceProviderServiceExtensions
班上Microsoft.Extensions.DependencyInjection.Abstractions库中同时实现了通用版GetService<T>()
和GetRequiredService<T>()
方法,以下所示:
我已经从本文的代码中删除了一些前提条件检查; 若是你想看到完整的代码,请在GitHub上查看。
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
一般是你正在使用服务定位器反模式的一个标志,因此通常应避免使用ISeviceProvider
。可是,若是因为设计限制而须要(例如,您不能在属性中使用DI),或者做为DI容器配置自己的一部分的状况下,您应该使用哪种呢?
基于GitHub中要求添加GetRequiredService()
的原始问题,以及Jeremy D. Miller先前提出的问题 ,我认为几乎全部状况下的规则是:
使用
GetRequiredService()
GetRequiredService()
会当即抛出异常。若是您使用GetService()
,那么您须要在调用代码中检查是否为null
,而且一般须要抛出异常。那个空检查代码须要在任何地方重复。GetService()
时忘记检查是否为null
,那么稍后您的程序可能会以NullReferenceException
结束。找出致使异常的缘由老是比显式的告诉你的InvalidOperationException
更困难,须要作更多的工做。GetRequiredService()
,则第三方容器自己会生成异常,所以能够提供其余特定于容器的信息。只返回null
(带GetService()
)不会给你进一步的详细的信息。这是引入GetRequiredService()
的主要缘由。固然,我已经看到了一些反对GetRequiredService()`的观点,但我认为其中任何一个都不会受到审查:
ISupportRequiredService
),那么您将没法经过使用任何其余诊断获益GetRequiredService()
。可是,我认为前两个优点仍然存在,并使GetRequiredService
值得使用。此外,若是您之后添加第三方容器,您已经在使用最佳实践了。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/