SimpleInjector 懒惰地注册所有

SimpleInjector RegisterAll lazily

使用 SimpleInjector,我可以像这样轻松地注册一个具体类型的多个实例:

var config = MyConfig.Load("myconfig.xml");
this.container.RegisterAll<IFoo>(config.FooNamesToCreate.Select(name => new Foo(name)));

这样做的缺点是 Foo 的所有实例都将在应用程序启动时的注册过程中立即创建。

如何注册所有这些相同类型的实例 Foo 但是将它们的 creation/instantiation 推迟到 IEnumerable<IFoo>[=26 的第一个请求=] ?

恕我直言,我需要这样的东西:

foreach(var name in config.FooNamesToCreate)
{
    var nameToUse = name; // probably needed for closure
    this.container.AddRegistration<IFoo>(() => new Foo(nameToUse));
}

我能想到的解决方案是抽象工厂,但我想知道 SimpleInjector 中是否有内置方法。

The downside of this is that all instances of Foo will be created right away during registration at the start of the application.

不,这是不正确的。

集合有两种,Simple Injector 关注的。容器控制的集合和容器不受控的集合。容器控制意味着 Simple Injector 控制集合实例的创建、自动装配和生命周期。 Container-uncontrolled 意味着您向简单注入器提供一个 IEnumerable,它基本上只是将 IEnumerable<T> 按原样注入任何消费者。

您在 RegisterAll<IFoo>(config.FooNamesToCreate.Select(name => new Foo(name))) 的注册不受容器控制,因为您将调用 RegisterAll<T>(IEnumerable<T>)。换句话说,Simple Injector 不会为您迭代该集合。只有当你调用 container.Verify() 时,Simple Injector 才会迭代它。所以当你调用RegisterAll<IFoo>(config.FooNamesToCreate.Select(name => new Foo(name)))时,发生的事情是调用FooNamesToCreate属性并调用Enumerable.Select方法来包装FooNamesToCreate属性 return 带有 select 枚举器的值。

但也许您想要更懒惰的行为,例如因为:

  • 您不希望 config.FooNamesToCreate 在应用程序启动期间被调用,或者
  • 您不希望在调用 Verify() 时枚举 Foo 个实例。

在这种情况下,您可以执行以下操作:

var config = MyConfig.Load("myconfig.xml");
container.RegisterSingle<IEnumerable<IFoo>>(
    () => config.FooNamesToCreate.Select(name => new Foo(name)));

这样做是将一个 IEnumerable<IFoo> 注册为单例(这与 RegisterAll<IFoo> 所做的基本相同),但是由于您提供了一个委托,您可以让集合本身被解析懒洋洋。这样做时,您将失去 Simple Injector 在调用 Verify() 时为您提供的验证支持,这可能正是您想要的。

请注意,尽管我们调用 RegisterSingle,但结果将是一个 IEnumerable<IFoo>,每次迭代可枚举时都会生成 Foo 的新实例。如果您希望 Foo 也成为单例,只需在 Select(name => new Foo(name)).

之后调用 .ToArray()