将 Transient 注入 Singleton 时肯定有什么问题?

hcp*_*hcp 4 .net c# dependency-injection simple-injector di-containers

存在一个问题,即Mark Seemann未正确配置名为Captive Dependency的DI 容器。例如,很明显,当“PerCall”依赖项被注入到“Singleton”依赖项中时。但是当“Transient”被注入到“Singleton”中时的场景呢?对我来说,为什么我不应该对某些场景(例如注册为瞬态注入到单例服务并永远存在于那里的计时器)执行特别操作的原因并不是很明显。

SimpleInjector DI 容器中有Lifestyle Mismatches 诊断警告。描述说:

瞬态组件依赖于单例是安全的,但反过来不行

为什么不好?在这种情况下,坏事的好例子将非常有用。当它“总是”糟糕或可以允许某些场景时是否有任何限制(参见我上面的示例)?

mtk*_*nko 9

这是不安全的,因为您的瞬态实例将永远在单例中。

示例:您可以将单例注入到另一个类实例中。在这种情况下,您也将间接注入瞬态实例。例如,您可能会面临线程安全问题。

如果您将类注册为单例,您会将其视为线程安全的,因为您可以在几个线程中同时使用相同的实例。如果您将类注册为瞬态类,那么它很可能是一个轻量级而不是线程安全的类。这就是为什么您将其注册为瞬态而不是单例的原因,对吗?这就是为什么您会看到警告:并发使用瞬态对象是不安全的。在 asp.net core 嵌入式 IoC 中,在这种情况下您将面临运行时异常。

想象一下:您的瞬态类SqlConnection在内部创建并在其生命周期内保持打开状态,并允许在不同步的情况下使用它。这没关系,因为它被认为在一个线程中存在一小段时间。然后将它注入到单例中,然后在每个请求中使用这个单例。

  • 我知道瞬态实例将永远存在于单例中。您能否提供更详细的示例,什么时候可能会很糟糕?“线程安全”问题这个词太笼统了。能举个更详细的例子吗?可能是一些代码?谢谢。 (3认同)
  • @PanagiotisKanavos:“单例保留对调用范围结束时释放的实例的引用。”。这种说法并不完全正确。例如,对于 MS.DI,注入到单例中的瞬态仅在容器被处置时才被处置。另一方面,使用简单注入器,瞬变*永远不会*被处理。 (2认同)

Ste*_*ven 8

这取决于您对“瞬态”实际含义的定义。Simple Injector 文档说明

Simple Injector 认为瞬态配准只持续很短的时间;临时的,即短暂的,不能重复使用。出于这个原因,Simple Injector 防止将瞬态组件注入到单例消费者中,因为它们预计寿命更长,否则会导致生活方式不匹配。

其他一些 DI 容器对“瞬态”使用不同的定义。例如,.NET Core DI 容器 (MS.DI) 建议您的瞬态注册是“轻量级、无状态服务”。因为它们被假定为无状态,所以将它们注入具有任何其他生命周期的使用者是安全的,只要他们没有自己的任何有状态(子)依赖项。“有状态”,在 MS.DI 的上下文中,通常意味着作用域依赖。MS.DI 对瞬态的定义与 Autofac 所称的Instance Per Dependency 相同。IMO,Autofac 的命名比较正确,因为从概念上来说,transient 的两个定义有很大的区别,相信大部分 DI Containers 都遵循“只持续很短的时间;临时的

只要您的 Transient 组件是无状态的,并且该组件不包含有状态的依赖项,将它注入到单例(或作用域)消费者中就没有坏处。然而,将这样的无状态组件注入到单例中,仍然会使该组件长寿命,这与短寿命完全不同。由于 Simple Injector 不知道您的组件是否包含状态,它认为所有瞬态都是短暂的,因此会警告您将瞬态注入到单例中。

更新:默认情况下,Simple Injector v5 现在允许将Transient组件注入Scoped. 此处将对此进行更详细的讨论。