IServiceLocator.GetInstance(Type)与IServiceProvider.GetServic

本文关键字:IServiceProvider GetServic Type GetInstance IServiceLocator | 更新日期: 2023-09-27 17:59:27

方法签名IServiceProvider.GetService(Type serviceType)IServiceLocator.GetInstance(Type serviceType)的意图有区别吗?如果是,区别是什么?

我一直把它们视为等价的,但为了保持一致性,我选择了使用单一的方法。对于处理这两个接口来说,这似乎是一个足够好的解决方案,但我真的很想知道它们的实际用途,这样我就可以确保在正确的地方使用正确的接口如果它们的意图实际上是相同的,那么有什么理由为同一目的使用多组语义吗(我知道GetInstance签名是在Microsoft.Practices.ServiceLocation开始时推荐的,但这似乎并不是引入重复的合理理由)。

为什么我感到困惑

以下是我在试图找到这个问题的答案时发现的一些有时相互矛盾的事实,以及我对这些事实的解释。我将这些内容包括在内,以便我的问题能够在有关该主题的所有已知信息的背景下得到解决。

  • MSDN中IServiceProvider的文档指出GetService(Type serviceType)方法应该返回

    类型为serviceType的服务对象
    -或-
    如果没有serviceType类型的服务对象,则为null。
  • IServiceLocator的MSDN文档缺少方法文档,但GetInstance(Type serviceType)的VS对象浏览器中的摘要显示该方法返回"请求的服务实例"。但是,文档IServiceLocator中也有一个异常条目,指出如果解析服务实例时出错,则应抛出ActivationException

  • ActivationException位于Microsoft.Practices.ServiceLocation名称空间中,该名称空间是在IServiceProvider引入多年后引入的。因此,IServiceProvider不引用异常是可以理解的。也就是说,IServiceLocator接口的文档没有说明如果找不到结果,将返回null。也不清楚缺少所请求服务类型的实现是否应该构成异常。

  • 缺少服务类型的实现是否会导致IServiceLocator实现中出现ActivationException它看起来不像。IServiceLocator的实现模板忽略了任何非null post条件的概念。

  • CCD_ 20的实现模板还将CCD_ 21作为CCD_。这算不算违反Liskov(由于在子类型中抛出未在基类型上声明的异常),或者,这实际上需要实现中的差异,而不是在接口的方法签名上声明的例外?我的意思是:我们确定IServiceLocatorServiceLocatorImplBase实现模板正确地实现了这两个接口吗对于IServiceProvider来说,将GetInstance调用封装在try块中,并在捕捉到异常时返回null,这会更好地表示接口的意图吗?

  • 附录:与此相关的另一个问题是IServiceLocator.GetAllInstances(Type)IServiceLocator.GetInstance(Type)的对应关系。具体来说,对于任何类型T,IServiceLocator.GetAllInstances(typeof(T))的实现是否应该返回与IServiceLocator.GetInstance(typeof(IEnumerable<>).MakeGenericType(typeof(T))相同的结果(很容易看出这与IServiceProvider对应关系,但我认为最好保持问题简单,在这种情况下只比较同一接口的两种方法。)

IServiceLocator.GetInstance(Type)与IServiceProvider.GetServic

正如您已经注意到的,IServiceProvider.GetServiceIServiceLocator.GetInstance之间的区别在于,当服务未注册或由于任何原因无法解决时,任何IServiceProvider.GetService实现都应该返回null,而IServiceLocator.GetInstance实现在这种情况下应该抛出异常(永远不要返回null)。

但请注意我使用了"应该"这个词。公共服务定位器项目(拥有IServiceLocator接口)附带的所有CSL适配器(用于Windsor、Spring、Unity和StructureMap等)都不遵守IServiceProvider接口,并且当您调用它们的IServiceProvider.GetService方法时,它们会抛出异常。

CSL的设计者违反了合同,使IServiceProvider接口变得毫无用处。您现在不能再依赖它返回null了,这很糟糕。真的很糟糕。据我所知,唯一遵守合同的CSL适配器是Simple Injector适配器,但由于所有其他实现都已损坏,因此即使是这个正确实现的适配器在这一点上也毫无用处,因为您无法安全地交换实现。

这算不算违反利斯科夫

当然。它们破坏了接口契约,实现不能相互替代。

设计师们知道这一点,可以从Glenn Block对这个帖子的评论中看出:

听起来我们可能搞砸了。抛出例外是一个明确的设计目标,我们都同意实现IServiceProvider更方便,但听起来这一点被忽视了。

该漏洞从未被修复,因为CSL从未更新过。

我认为你没有提到的两种设计之间有一个区别:

IServiceProvider.GetService
如果没有serviceType类型的服务对象,则为null。

IServiceLocator.GetInstance
如果解析服务实例时出错,则应引发ActivationException。

需要注意的是,一个指定默认情况,另一个指定错误情况。它们不一样是有道理的。

从提供的示例来看,组合似乎是预期的实现。null作为默认值,出现错误时包装ActivationException。

编辑:

具体来说,对于任何类型T,IServiceLocator.GetAllInstances(typeof(T))的实现是否应该返回与IServiceLocator.GetInstance(typeof?

typeof(IEnumerable<T>)不是更紧凑的形式吗?此外,当要求IEnumerable类型时,为什么GetInstance会返回任何内容?你可以用这种方式实现它,但我不认为它是自动的。

相关文章:
  • 没有找到相关文章