StructureMap has some built in functionality for "lazy" resolved dependencies, so that instead of your
application service taking a direct dependency on
IExpensiveToBuildService
that might not be necessary,
you could instead have StructureMap fulfil a dependency on
Lazy<IExpensiveToBuildService>
or
Func<IExpensiveToBuildService>
that could be used to retrieve that expensive service only when it is needed from whatever
Container
originally created
the parent object.
Do note that the
Lazy<T>
and
Func<T>
approaches respect the lifecycle of the underlying registration rather than
automatically building a unique object instance.
Also note that
Lazy<T>
or
Func<T>
is your best (only) viable approach if you wish to have StructureMap inject bi-directional
relationships.
Lazy<T>
Assuming that StructureMap either has an existing configuration for
T
or can
derive a way to build
T
, you can just declare a dependency on
Lazy<T>
like this sample:
public class WidgetLazyUser
private readonly Lazy<IWidget> _widget;
public WidgetLazyUser(Lazy<IWidget> widget)
_widget = widget;
public IWidget Widget
get { return _widget.Value; }
[Fact]
public void lazy_resolution_in_action()
var container = new Container(_ =>
_.For<IWidget>().Use<AWidget>();
container.GetInstance<WidgetLazyUser>()
.Widget.ShouldBeOfType<AWidget>();
Func<T>
Likewise, you can also declare a dependency on
Func<T>
with very similar mechanics:
[Fact]
public void build_a_func_that_returns_a_singleton()
var container = new Container(x =>
x.ForSingletonOf<IWidget>().Use<ColorWidget>().Ctor<string>("color").Is("green");
var func = container.GetInstance<Func<IWidget>>();
var w1 = func();
var w2 = func();
var w3 = func();
w1.ShouldBeOfType<ColorWidget>().Color.ShouldBe("green");
w1.ShouldBeTheSameAs(w2);
w1.ShouldBeTheSameAs(w3);
w2.ShouldBeTheSameAs(w3);
This functionality predates the introduction of the Lazy type to .Net
Func<string, T>
Finally, you can also declare a dependency on
Func<string, T>
that will allow you to lazily
resolve a dependency of
T
by name:
[Fact]
public void build_a_func_by_string()
var container = new Container(x =>
x.For<IWidget>().Add<ColorWidget>().Ctor<string>("color").Is("green").Named("green");
x.For<IWidget>().Add<ColorWidget>().Ctor<string>("color").Is("blue").Named("blue");
x.For<IWidget>().Add<ColorWidget>().Ctor<string>("color").Is("red").Named("red");
var func = container.GetInstance<Func<string, IWidget>>();
func("green").ShouldBeOfType<ColorWidget>().Color.ShouldBe("green");
Bi-relational Dependency Workaround
StructureMap does not directly support bi-directional dependency relationships
-- but will happily tell you in an exception when
you accidentally manage to create one without cratering your AppDomain with a
StackOverflowException
.
Either
Func<T>
or
Lazy<T>
can be used as a workaround for purposeful bi-directional dependencies between types. The
following is an example of using this strategy:
[Singleton]
public class Thing1
private readonly Lazy<Thing2> _thing2;
public Thing1(Lazy<Thing2> thing2)
_thing2 = thing2;
public Thing2 Thing2
get { return _thing2.Value; }
[Singleton]
public class Thing2
public Thing1 Thing1 { get; set; }
public Thing2(Thing1 thing1)
Thing1 = thing1;
[Fact]
public void use_lazy_as_workaround_for_bi_directional_dependency()
var container = new Container();
var thing1 = container.GetInstance<Thing1>();
var thing2 = container.GetInstance<Thing2>();
thing1.Thing2.ShouldBeSameAs(thing2);
thing2.Thing1.ShouldBeSameAs(thing1);