Does structuremap allow you to do constructor injection in a lazy fashion? Meaning not creating the object which is injected until it is used?
UPDATE: StructureMap v3 implements this out of the box, so this trick is no longer necessary.
StructureMap version 2 doesn't, but with a few tricks you can get it to do what I believe you are looking for. First of all, you can already wire up Lazy
instances manually like this:
container = new Container(x =>
{
x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
});
x.For>().Use(y => new Lazy(y.GetInstance));
x.For>().Use(y => new Lazy(y.GetInstance));
x.For>().Use(y => new Lazy(y.GetInstance));
});
This works just fine, but you have to register each and every type individually. It would be nicer if you could take advantage of a more convention-based approach. Ideally, the following syntax would be nice.
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));
This syntax actually works... somewhat. Unfortunately, at runtime, StructureMap will attempt to find the "greediest" constructor for Lazy
and settle on public Lazy(Func
. Since we didn't tell it what to do with the boolean isThreadSafe parameter, it will throw an exception when it tries to resolve `Lazy'.
The documentation for Lazy states that the "thread safety mode" of the default Lazy(Func
constructor is LazyThreadSafetyMode.ExecutionAndPublication
, which just so happens to be what you get by passing true into the isThreadSafe parameter of the constructor above. So, if we could just tell StructureMap to pass true
for isThreadSafe
, we would get the same behavior as if we called the constructor we actually wanted to use in the first place (e.g. Lazy(Func
).
Simply registering x.For(typeof(bool)).Use(y => true)
would be very reckless and dangerous since we would be telling StructureMap to go ahead and use the value true
for any boolean anywhere. Instead, we need to tell StructureMap what value to use for just this one boolean parameter, which we can do like this.
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>))
.CtorDependency("isThreadSafe").Is(true);
StructureMap now knows to use the value of "true" for the isThreadSafe parameter when resolving Lazy
. We can now use Lazy
in constructor parameters, and get the behavior I believe you were looking for.
You can read about the Lazy class in more detail here.