views:

82

answers:

3

Sometimes I have classes which need to get some information for construction. I am not talking about references to other objects (which will be injected) but about (for instance) strings which are holding unique information:

// Scoped as singleton!
class Repository
{
    public Repository( InjectedObject injectedObject, string path ) { ... }
}

How do you get this string injected? One possiblity is to write an Init() method and to avoid injection for the string:

class Repository
{
    public Repository( InjectedObject injectedObject ) { ... }
    public void Init( string path ) { ... }
}

Another possibility is to wrap the information into an object, which can be injected:

class InjectedRepositoryPath
{
    public InjectedRepositoryPath( string path ) { ... }
    public string Path { get; private set; }
}

class Repository
{
    public Repository( InjectedObject injectedObject, InjectedRepositoryPath path ) { ... }
}

This way I'd have to create an instance of InjectedRepositoryPath during the initialisation of my DI-Container and register this instance. But I need such an unique configuration object for every similar class.

Of course I can resolve a RepositryFactory instead of the Repository object, so the factory would ask me for the path:

class RepositoryFactory
{
    Repository Create( string path ) { ... }
}

But again, this is one factory just for a singleton object ...
Or, finally, since the path will be extracted from a configuration file, I could skip passing around the string and read the config in my constructor (which is probably not as optimal, but possible):

class Repository
{
    public Repository( InjectedObject injectedObject )
    {
        // Read the path from app's config
    }
}

What's your favorite method? For non-singleton classes you have to use imho the Init() or factory solution, but what about singleton-scoped objects?

+3  A: 

If you are using Constructor injection I find adding a parameter which is your configuration object to the constructor is the best way. By using an init function you are somewhat sidestepping the point of constructor injection. This makes testing harder, it also makes maintenance and delivery more difficult.

Discovery becomes a problem because it is not readily apparent that this class requires a configuration object. By adding it to the constructor anyone using this object knows explicitly that this configuration must be there.

Jeremy B.
I too feel the same way.
Kangkan
+2  A: 

I prefer not having a DI Container dictate my API design. The container should conform to proper design, not the other way around.

Design your classes in a DI-friendly manner, but without making concessions to your DI Container. If you need a connection string, then take a string through the constructor:

public class Repository : IRepository
{
    public Repository(string path) { //... }
}

Many DI Containers can deal with primitive values. As an example, here's one way to do it with Windsor:

container.Register(Component.For<IRepository>()
    .ImplementedBy<Repository>()
    .DependsOn( new { path = "myPath" } ));

However, if your container of choice can't deal with primitive parameters, you can always decorate Repository with an implementation that knows how to find the string:

public class ConfiguredRepository : IRepository
{
    private readonly Repository decoratedRepository;

    public ConfiguredRepository()
    {
        string path = // get the path from config, or whereever appropriate
        this.decoratedRepository = new Repository(path);
    }

    // Implement the rest of IRepository by
    // delegating to this.decoratedRepository
}

Now you can simply tell your container to map IRepository to ConfiguredRepository, while still keeping the core Repository implementation clean.

Mark Seemann
Very interesting link, thanks for the answer!
tanascius
+1  A: 

Some time ago, Joshua Flanagan showed how custom configuration sections can be treated like dependencies, and provided via constructor injection.

http://www.lostechies.com/blogs/joshuaflanagan/archive/2009/07/12/how-we-handle-application-configuration.aspx

Grant Palin
thanks for the interesting link!
tanascius