views:

69

answers:

2

I have a service class which has overloaded constructors. One constructor has 5 parameters and the other has 4.

Before I call,

var service = IoC.Resolve<IService>();

I want to do a test and based on the result of this test, resolve service using a specific constructor. In other words,

        bool testPassed = CheckCertainConditions();
        if (testPassed)
        {
            //Resolve service using 5 paramater constructor
        }
        else
        {
            //Resolve service using 4 parameter constructor
            //If I use 5 parameter constructor under these conditions I will have epic fail.
        }

Is there a way I can specify which one I want to use?

+1  A: 

In general, you should watch out for ambiguity in constructors when it comes to DI because you are essentially saying to any caller that 'I don't really care if you use one or the other'. This is unlikely to be what you intended.

However, one container-agnostic solution is to wrap the conditional implementation into another class that implements the same interface:

public class ConditionalService : IService
{
    private readonly IService service;

    public ConditionalService()
    {
        bool testPassed = CheckCertainConditions();      
        if (testPassed)      
        {      
            // assign this.service using 5 paramater constructor      
        }      
        else      
        {      
            // assign this.service using 4 parameter constructor
        }  
    }

    // assuming that IService has a Foo method:
    public IBaz Foo(IBar bar)
    {
        return this.service.Foo(bar);
    }
}

If you can't perform the CheckCertainConditions check in the constructor, you can use lazy evaluation instead.

It would be a good idea to let ConditionalService request all dependencies via Constructor Injection, but I left that out of the example code.

You can register ConditionalService with the DI Container instead of the real implementation.

Mark Seemann
A: 

My underlying problem was that I was trying to resolve my class which had the following signature:

public DatabaseSchemaSynchronisationService(IDatabaseService databaseService, IUserSessionManager userSessionManager)

This was basically useless to me because my usersessionmanager had no active NHibernate.ISession because a connection to my database had not yet been made. What I was trying to do was check if I did have a connection and only then resolve this class which served as a service to run database update scripts.

When changing my whole class to perform the scripts in a different way, all I needed in its constructor's signature was:

public DatabaseSchemaSynchronisationService(ISessionFactory sessionFactory)

This allowed me to open my own session. I did, however have to first check if the connection was ready before attempting to resolve the class, but having IDatabaseSchemaSynchronisationService as a parameter to another class's constructor; this class also gettting resolved somewhere where I could not check the db connection was a bad idea.

Instead in this second class, I took the IDatabaseSchemaSynchronisationService paramater out of the constructor signature and made it a local variable which only gets instantiated (resolved) :

if (connectionIsReady)

Thanks to everyone who answered.

Corpsekicker