views:

71

answers:

1

A class has a unique constructor taking IMyInterface as its argument. If I define a concrete type of IMyInterface and registers it to StructureMap then there is no issue and my class can be instanciated with this concrete type.

However, in some cases, no concrete type will be registered. In that case, I would like to receive null for the IMyInterface parameter. Instead I get an exception:

StructureMap Exception Code: 202 No Default Instance defined for PluginFamily IMyInterface.

Is it possible to define a default value for a missing plugin?

Context: my class, which is a service, uses the Spark view engine and defines some default namespaces. The service uses a ISparkNamespacesProvider (IMyInterface) to add aditional namespaces. The client app may register such a provider or not. That's why the constructor of the service will receive either a provider or none.

+1  A: 

Taken from here:

For<IService>().Use<MyService>()
 .Ctor<IMyInterface>("nameOfParameter").Is(null);

But You should think about why Your class is dependent on IMyInterface. If it's optional - that's a code smell. Maybe You should refactor it out as method argument for method that needs it or as settable property.

There shouldn't be need for switching between concrete implementation and null. When composing dependency graph at composition root, You should know exactly what will be Your dependencies w/o .If(isSomething()).Use<MyService>().Ctor<IMyInterface>(null).

You might want to check out this tekpub presentation and this book (look for so called MEAP access) about DI and IOC.


One way to accomplish what You want is using so called 'poor man dependency injection'. That is - to define second constructor:

public MyClass():this(null){...}

But I wouldn't recommend that.

Arnis L.
null has to be cast to IMyInterface to avoid an ambiguous call. And unfortunately it doesn't work. When I define a concrete type and registers it to SM, null is still passed. So it seems your code does not define a default param but a forced value for this param. If I remove your code, the concrete type is used.
Nicolas Cadilhac
@Nicolas There should be only one concrete implementation specified at configuration. Otherwise - Your design quite likely is wrong.
Arnis L.
@Nicolas maybe You could post here class that takes `IMyInterface`? Constructor and part that uses `IMyInterface`.
Arnis L.
@Nicolas why exactly there are cases where concrete implementation is unknown?
Arnis L.
I'm not switching between null or a concrete type dynamically. At init time, I either define a concrete type or none (in other terms, client app A will define one, and client app B will define none).
Nicolas Cadilhac
@Nicolas So - there are 2 composition roots. Client app A should have it's own structuremap registry, separated from client app B (they can have shared parts to avoid dupe code). That does not eliminate my doubts that optional dependency shouldn't be passed through ctor though.
Arnis L.
I can't define a second constrcutor like that. SM would choose the first one except if I force it to always should the second one.
Nicolas Cadilhac
Yeah, that part of my answer is wrong. Anyway - You should definitely write 2nd composition root and consider if that dependency is really dependency for whole class.
Arnis L.
@Arnie - "There should be only one concrete implementation specified at configuration. Otherwise - Your design quite likely is wrong." Huh? One of the great things about interfaces is that it allows you to vary behavior without the consumer knowing about it.That said, I think wanting to pass null in some cases is a code smell, if anything you might want to implement a null version of the interface, much like your might have a null log writer that does nothing. See http://en.wikipedia.org/wiki/Null_Object_pattern for a better explanation.
Robin Clowers
@Robin - This is exactly the temporary workaround I have: a default implementation of the interface which returns an empty collection of namespaces.
Nicolas Cadilhac
@Robin not that. abstractions are for making code more loosely coupled indeed but that's not what I'm talking about. I'm talking about composition root configuration - SM registries, initialization of them. at that point - there should be known one specific implementation. Otherwise - there are 2 composition roots.
Arnis L.