IServiceLocator.GetInstance(Type)的意图与IServiceProvider.GetService(Type)的意图有何不同?

sma*_*man 11 c# dependency-injection common-service-locator service-locator base-class-library

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

我总是将它们视为等效的,但可以选择使用单一方法来保持一致性.对于处理这两个接口来说,这似乎是一个很好的解决方案,但我真的很想知道它们的用法是如何实际的,这样我才能确定我在正确的位置使用正确的用法. 如果他们的意图实际上是相同的,那么是否有任何理由为同一目的设置多组语义?(据我所知,GetInstance出现之初被推荐的签名Microsoft.Practices.ServiceLocation,但是这并没有真正看起来像一个充分的理由,介绍重复).

为什么我很困惑

以下是我在试图找到这个问题的答案时发现的有时相互矛盾的事实清单,以及我对此的解释.我将这些内容包含在内,以便可以在已知有关该主题的所有信息的上下文中解决我的问题.

  • 为MSDN文档IServiceProvider说,该GetService(Type serviceType)方法应该返回

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

  • ActivationException位于Microsoft.Practices.ServiceLocation引入多年后IServiceProvider引入的命名空间中.因此,可以理解的是,IServiceProvider它并未引用异常.话虽这么说,如果没有找到结果,IServiceLocator界面的文档没有说明返回null.还不清楚是否缺乏所要求的服务类型的实施应构成例外.

  • 如果没有为服务类型的实现会导致ActivationExceptionIServiceLocator实现? 看起来不像.用于忽略非空后置条件的任何概念的实现模板IServiceLocator.

  • 实施模板IServiceLocator也把IServiceProvider.GetService(Type)作为替代语法IServiceLocator.GetInstance().这是否违反Liskov(由于在基类型上未声明的子类型中抛出异常),或者,实际上是否需要在实现中有所不同,而不是在接口的方法签名上声明的异常?我得到的是:我们确定实现的ServiceLocatorImplBase实现模板IServiceLocator都正确接口吗? 它是否更好地表示接口在try块中IServiceProvider包装GetInstance调用的意图,并null在捕获异常时返回?

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

Ste*_*ven 11

正如你已经注意到,之间的区别IServiceProvider.GetService,并IServiceLocator.GetInstance为任何IServiceProvider.GetService实现返回null时,该服务未注册或当它不能什么都原因加以解决,而IServiceLocator.GetInstance在另一方面实现应该扔在这种情况下,异常(和永远不会回来null).

但请注意我使用"应该"这个词.Common Service Locator项目(拥有该IServiceLocator接口)附带的所有CSL适配器(用于Windsor,Spring,Unity和StructureMap等)都不遵守IServiceProvider接口,并且在调用其IServiceProvider.GetService方法时会抛出异常.

通过违反合同,CSL的设计者设法使IServiceProvider界面毫无用处.你现在根本不能再依赖它来返回null,这很糟糕.特别糟糕.我所知道的唯一符合合同的CSL适配器是Simple Injector适配器,但由于所有其他实现都被破坏,即使这个正确实现的适配器在那时也没用,因为你无法安全地交换实现.

这是否违反Liskov

绝对.他们违反了接口合同,实现无法互相替代.

设计师知道这一点,从Glenn Block对此主题的评论中可以看出:

听起来我们可能搞砸了.抛出异常的想法是我们都同意的一个明确的设计目标.使它实现IServiceProvider更方便,但听起来像这样被忽略了.

该缺陷从未得到修复,因为CSL从未更新过.