我对ContextDependentExtensions
SimpleInjector
库有疑问。
我们有以下扩展,以增加使用某些上下文向注入器中添加元素的可能性:ContextDependentExtensions
示例:
var container = new Container();
container.RegisterWithContext(logger => new SimpleLogger("Logger Constructor Parameter"));
这是一条兴趣线: Should always be transient!
那么,这是什么意思?我们可以在这里使用Lifestyle.Singleton
或Lifestyle.Scoped
生活方式吗?
有人可以帮我解释一下吗? 提前谢谢。
答案 0 :(得分:2)
使用RegisterWithContext
扩展方法,您可以注册一个谓词,该谓词允许您使用有关使用组件的信息构建实例。此信息通过扩展方法提供给谓词。
因为这意味着您可以为每种消费类型构建一个完全不同的实例,使注册除了瞬态之外的任何其他内容都可能导致非常奇怪的行为。例如,想象一下ILogger
抽象的注册,您可以在其中创建Logger<T>
实现,其中T
是消费组件的类型:
container.RegisterWithContext(c =>
(ILogger).container.GetInstance(
typeof(Logger<>).MakeGenericType(c.ImplementationType)));
如果您要进行此注册单例,这将导致问题,即使消费组件是单例,因为相同的实例将注入每个消费者;虽然每个消费者都需要他们自己的实例,因为他们需要自己的封闭通用版本,即:Logger<Consumer1>
,Logger<Consumer2>
,Logger<Consumer3>
等。相反,非常消费者会获得相同的实例;为第一个已解析的使用者创建的实例。这显然很糟糕。
使用Scoped实例时也会存在同样的问题;你会在范围的持续时间内获得相同的实例,这通常不是你想要的;实例应该依赖于上下文。
这是Simple Injector v2文档提供的RegisterWithContext
扩展方法的严重限制。由于这个限制太多,Simple Injector v3现在包含一个内置的RegisterConditional
方法,它取代了RegisterWithContext
扩展方法。 v3文档不再引用RegisterWithContext
,我们建议改为使用RegisterWithContext
。
文档describes如何使用RegisterConditional
并显示以下示例:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
由于此注册的谓词返回true
,因此注册不是真正有条件的,而只是上下文。
使用此代码,您可以返回特定于消费组件的Logger<T>
,但仍然确保每个关闭的Logger<T>
类型最多只有一个实例;因此是一个单身人士。
新RegisterConditional
和旧RegisterWithContext
之间的主要区别在于您无法提供工厂委托来创建实例。使用RegisterConditional
,Simple Injector可以控制实例的创建(而不是您的委托),这样就可以将类型的创建完全合并到管道中,并允许Simple Injector验证和诊断已注册的组件及其依赖项。