哈哈镜打一成语,恶俗维基,青岛电缆
上篇文章《在.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
- 如果发生异常,第三方容器可能就会根据异常信息提供相应的诊断信息,以便您可以找出未注册预期服务的原因。
asp.net core依赖注入抽象的核心是iserviceprovider
接口。该接口实际上是system
命名空间中基类库的一部分。接口本身很简单:
public interface iserviceprovider { object getservice(type servicetype); }
一旦您使用di容器(使用iservicecollection
)注册了所有类,几乎所有di容器需要做的就是允许您使用getservice()
查找对象的实例。
当然,您通常根本不应该直接在代码中使用iserviceprovider
。相反,您应该使用标准的构造函数注入,并让框架来承载并在幕后使用iserviceprovider
。
直接使用
iserviceprovider
是服务定位器模式的一个示例。这,因为它隐藏了类的依赖关系。
然而,有些时候你没有选择的余地。例如,如果您试图,或者,则需要直接使用iserviceprovider
。
鉴于我们不再使用.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()
。
如果iserviceprovider
没有实现isupportrequiredservice
,则执行所需的异常抛出行为,如您所料:getservice()
调用,如果返回null
则抛出异常。
正如我之前所说,理想情况下,两者都可以!
在您自己的代码使用iseviceprovider
通常是你正在使用的一个标志,所以一般应避免使用iseviceprovider
。但是,如果由于设计限制而需要(例如,您不能在属性中使用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容器。
原英文链接:
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Net Core Web Api项目与在NginX下发布的方法
asp.net core3.1 引用的元包dll版本兼容性问题解决方案
IdentityServer4实现.Net Core API接口权限认证(快速入门)
ASP.NET Core MVC通过IViewLocationExpander扩展视图搜索路径的实现
网友评论