ContextDependent实例作为Simple Injector中的Singleton

时间:2016-05-09 11:45:36

标签: c# .net simple-injector

我对ContextDependentExtensions SimpleInjector库有疑问。 我们有以下扩展,以增加使用某些上下文向注入器中添加元素的可能性:ContextDependentExtensions

示例:

var container = new Container();
container.RegisterWithContext(logger => new SimpleLogger("Logger Constructor Parameter"));

这是一条兴趣线: Should always be transient!

那么,这是什么意思?我们可以在这里使用Lifestyle.SingletonLifestyle.Scoped生活方式吗?

有人可以帮我解释一下吗? 提前谢谢。

1 个答案:

答案 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验证和诊断已注册的组件及其依赖项。