With SimpleInjector I can easily register multiple instances of a concrete type like so:
var config = MyConfig.Load("myconfig.xml");
this.container.RegisterAll<IFoo>(config.FooNamesToCreate.Select(name => new Foo(name)));
The downside of this is that all instances of Foo
will be created right away during registration at the start of the application.
How can I register all theses instances of the same concrate type Foo
but defer the creation/instantiation of them until the first request of IEnumerable<IFoo>
?
IMHO I'd need something like this:
foreach(var name in config.FooNamesToCreate)
{
var nameToUse = name; // probably needed for closure
this.container.AddRegistration<IFoo>(() => new Foo(nameToUse));
}
The solution for this I could come up with is abstract factory, but I wonder if there is a built-in way in SimpleInjector.
The downside of this is that all instances of Foo will be created right away during registration at the start of the application.
Nope, this is incorrect.
There are two types of collections, what Simple Injector is concerned. Container-controlled collections and container uncontrolled collections. Container-controlled means that Simple Injector is in control over the creation, auto-wiring, and lifetime of the instances of a collection. Container-uncontrolled means that you supply an IEnumerable to Simple Injector, and it will basically just inject that IEnumerable<T>
as-is into any consumer.
Your registration with RegisterAll<IFoo>(config.FooNamesToCreate.Select(name => new Foo(name)))
is container-uncontrolled, because you will call RegisterAll<T>(IEnumerable<T>)
. In other words, Simple Injector will not iterate that collection for you. Only if you call container.Verify()
, Simple Injector will iterate it. So when you call RegisterAll<IFoo>(config.FooNamesToCreate.Select(name => new Foo(name)))
, what happens is that the FooNamesToCreate
property is called and the Enumerable.Select
method is called to wrap the FooNamesToCreate
property return value with a select enumerator.
But perhaps you want behavior that is even more lazy, for instance because:
config.FooNamesToCreate
to be called during application start-up, orFoo
instances to be enumerated when Verify()
is called.In that case, you can do the following:
var config = MyConfig.Load("myconfig.xml");
container.RegisterSingle<IEnumerable<IFoo>>(
() => config.FooNamesToCreate.Select(name => new Foo(name)));
What this does is register an IEnumerable<IFoo>
as a singleton (which is basically the same as what RegisterAll<IFoo>
does), but since you supply a delegate, you can let the collection itself be resolved lazily. When doing this, you will lose verification support that Simple Injector gives you when calling Verify()
, which might be exactly what you want.
Do note though that even though we call RegisterSingle
, the result will be an IEnumerable<IFoo>
that will produce new instances of Foo
everytime that enumerable is iterated. If you want the Foo
s to be singletons as well, just call .ToArray()
after the Select(name => new Foo(name))
.