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

标签 c# dependency-injection service-locator base-class-library common-service-locator

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

我一直将它们视为等同的,但为了保持一致性,我选择使用单一方法。对于处理这两个接口(interface)来说,这似乎是一个足够好的解决方案,但我真的很想知道它们的实际用途是怎样的,这样我就可以确定我在正确的地方使用了正确的接口(interface)。 如果他们的意图实际上是相同的,那么是否有任何理由为了同一目的而使用多组语义?(我理解 the GetInstance signature was recommended during the inception of Microsoft.Practices.ServiceLocation ,但这看起来不像是一个声音引入重复的原因)。

为什么我很困惑

下面列出了我在试图找到这个问题的答案时发现的有时相互矛盾的事实,以及我对这些事实的解释。我将这些包括在内,以便我的问题可以在关于该主题的所有已知信息的上下文中得到解决。

  • MSDN documentation for IServiceProvider GetService(Type serviceType)方法应该返回

    A service object of type serviceType.
    -or-
    null if there is no service object of type serviceType.
  • MSDN documentation for IServiceLocator 缺少方法文档,但 VS 对象浏览器中的摘要 GetInstance(Type serviceType)表示该方法返回“请求的服务实例”。但是,文档中也有异常条目IServiceLocator那说 ActivationException如果解析服务实例时出现错误,则应抛出该异常。

  • ActivationException位于 Microsoft.Practices.ServiceLocationIServiceProvider 之后引入的 namespace 被介绍。所以,IServiceProvider 是可以理解的不指异常。也就是说,IServiceLocator接口(interface)的文档没有提到返回 null如果没有找到结果。还不清楚所请求服务类型的实现缺失是否应该构成异常。

  • 如果缺少服务类型的实现会导致 ActivationExceptionIServiceLocator实现? 看起来不像。 implementation template对于 IServiceLocator忽略任何非空后置条件的概念。

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

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

最佳答案

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

但请注意我使用了“应该”这个词。 Common Service Locator project 随附的所有 CSL 适配器(用于 Windsor、Spring、Unity 和 StructureMap 等) (它拥有 IServiceLocator 接口(interface))不遵守 IServiceProvider 接口(interface),当您调用它们的 IServiceProvider.GetService 方法时,它们会抛出异常。

通过破坏契约,CSL 的设计者设法使 IServiceProvider 接口(interface)完全无用。您现在不能再依赖它返回 null,这很糟糕。特别糟糕。我所知道的唯一遵守契约(Contract)的 CSL 适配器是 Simple Injector adapter ,但是由于所有其他实现都被破坏了,即使这个正确实现的适配器此时也没有用,因为您无法安全地交换实现。

Does this count as a violation of Liskov

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

设计者知道这一点,从Glenn Block可以看出对 this thread 的评论:

Sounds like we might have messed up here. The idea of throwing an exception was an explicit design goal that we all agreed on. Making it implement IServiceProvider was more of a convenience, but sounds like this was overlooked.

该缺陷从未修复,因为 CSL 从未更新过。

关于c# - IServiceLocator.GetInstance(Type) 的意图与 IServiceProvider.GetService(Type) 的意图有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14864108/

相关文章:

c# - 使用 MonoGame 和双指手势实现缩放

c# - asp.net 5 MVC6 中标记助手和 Route 属性之间的奇怪行为

c# - ASP.NET MVC3 + ActionFilterAttribute + 注入(inject)?

.net - 服务定位器 - 值得吗?

c# - 如何从外部调用 SignalR 集线器方法?

c# - 对通用对象使用 typeof C#

java - 构造函数注入(inject): How to reduce amount of parameters?

c# - 依赖注入(inject)。为 ASP.NET vNext 做准备

asp.net-mvc - ASP.NET MVC 中的服务定位器替代方案