Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StructureMap passing null in the constructor

I'm having a little difficulty with using StructureMap for services where there is a nullable argument in the constructor. I.e.

public JustGivingService(IRestClient restClient = null)

In my configuration, with all other services, I'm usually able to get away with the minimal, so the issue here is probably just a lack of understanding. I'd do this:

container.For<IJustGivingService>().Use<JustGivingService>()

However, because of the nullable parameter, I'll find that I'll need to use this instead to get it working:

RestClient restClient = null;
container.For<IJustGivingService>().Use<JustGivingService>()
    .Ctor<IRestClient>("restClient").Is(restClient);

However, this does feel a little dirty to me and I feel like this probably is a workaround for what I'm trying to achieve rather than the standard way to do it. If there is a better way to do this, accompanying information as to why would be greatly appreciated.

like image 582
ediblecode Avatar asked Apr 11 '16 10:04

ediblecode


1 Answers

StructureMap does not support optional constructor parameters, and it shouldn't. As described in this blog post:

An optional dependency implies that the reference to the dependency will be null when it’s not supplied. Null references complicate code because they require specific logic for the null-case. Instead of passing in a null reference, the caller could insert an implementation with no behavior, i.e. an implementation of the Null Object Pattern. This ensures that dependencies are always available, the type can require those dependencies and the dreaded null checks are gone. This means we have less code to maintain and test.

So the solution is to create a Null Object implementation for IRestClient and register that implementation in StructureMap.

Example:

// Null Object pattern
public sealed class EmptyRestClient : IRestClient {
    // Implement IRestClient methods to do nothing.
}

// Register in StructureMap
container.For<IRestClient>().Use(new EmptyRestClient());
like image 100
Steven Avatar answered Oct 28 '22 08:10

Steven