上篇文章《在.NET Core 3.0中的WPF中使用IOC图文教程》中,我们尝试在WPF中应用.NET Core内置的IOC进行编程,在解析MainWindow的时候我用了GetRequiredService<T>()方法,当时就在想这个GetRequiredService<T>()方法跟GetService<T>()到底有什么区别呢,于是乎,谷歌了一把,就发现了一篇文章来介绍他们区别的,于是乎尝试翻译一把,希望对大家有所帮助。文章最后会给出原文链接,以下就是翻译内容:
本文将介绍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是服务定位器模式的一个示例。这通常被认为是反模式,因为它隐藏了类的依赖关系。
然而,有些时候你没有选择的余地。例如,如果您试图将服务注入到属性,或者在配置DI容器时使用“转发”类型,则需要直接使用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库中同时实现了通用版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()。