views:

91

answers:

3

I've been researching Dependency Injection and Inversion of Control practices lately in an effort to improve the architecture of our application framework and I can't seem to find a good answer to this question. It's very likely that I have my terminology confused, mixed up, or that I'm just naive to the concept right now, so any links or clarification would be appreciated.

Many examples of DI and IoC containers don't illustrate how the container will connect things together when you have a "library" of possible "plugins", or how to "serialize" a given configuration. (From what I've read about MEF, having multiple declarations of [Export] for the same type will not work if your object only requires 1 [Import]). Maybe that's a different pattern or I'm blinded by my current way of thinking.

Here's some code for an example reference:

public abstract class Engine {
}

public class FastEngine : Engine {
}

public class MediumEngine : Engine {
}

public class SlowEngine : Engine {
}

public class Car
{
    public Car(Engine e)
    {
        engine = e;
    }

    private Engine engine;
}

This post talks about "Fine-grained context" where 2 instances of the same object need different implementations of the "Engine" class: http://stackoverflow.com/questions/2176833/ioc-resolve-vs-constructor-injection

Is there a good framework that helps you configure or serialize a configuration to achieve something like this without hard coding it or hand-rolling the code to do this?

public class Application
{
    public void Go()
    {
        Car c1 = new Car(new FastEngine());
        Car c2 = new Car(new SlowEngine());
    }
}

Sample XML:

<XML>
    <Cars>
        <Car name="c1" engine="FastEngine" />
        <Car name="c2" engine="SlowEngine" />
    </Cars>
</XML>
A: 

Using MEF (which you mentioned), you can use [ImportMany] to import a collection of Engine instances. You'd then be able to create one car per engine, and return that, with no XML required.

public class Application
{
    [ImportMany]
    public IEnumerable<Engine> Engines { get; set; }

    public void Go()
    {
        // I'm assuming this object was composed already...

        var cars = this.Engines.Select(e => new Car(e));

        foreach(var car in cars)
        {
            // Do something with each car
        }
    }
}

This has the advantage of allowing you to add new "Engines" any time, without changing your code. All of the wiring is handled dynamically at runtime without configuration.

Reed Copsey
Thanks Reed. I did find the [ImportMany] attribute in MEF, which seemed great for dynamically loading collections of things. I think the problem I'm trying to solve is allowing someone to be explicit about which object gets used for each Car. I can see using this approach how new Engine objects would be added to the list at runtime, but I need some way of serializing the fact that "Car 1 uses a Fast Engine", so when I create Car 1, give it a Fast Engine.
Joshua Starner
+1  A: 

I don't know about mef, but Spring does exactly what you describe using pretty much exactly the same method you describe (injection configured by an XML file or config section):

<objects>
  <object name="FastCar" type="MyApp.Car">
    <constructor-arg>
       <ref object="FastEngine">
    </constructor-arg>
  </object>
  <object name="SlowCar" type="MyApp.Car">
    <constructor-arg>
       <ref object="SlowEngine">
    </constructor-arg>     
  </object>
  <object name="FastEngine" type="MyApp.FastEngine"/>
  <object name="SlowEngine" type="MyApp.SlowEngine"/>
</objects>
Eric Petroelje
Cool, I've seen Spring mentioned, but I didn't pursue any further reading. I'll check it out. Thanks!
Joshua Starner
A: 

Most DI Containers support XML configuration - in fact, most of them started out that way, and XML configuration was the only option. Nowadays, XML configuration is one option among several.

However, in it's current incarnation, MEF doesn't use XML configuration. It's not a DI Container either.

Mark Seemann
Thanks for the link. Now that I've read more on MEF, I don't think unknown runtime discovery is what I'm looking for.It looks like an open debate between XML Configuration and Code Configuration. Ultimately, I'd like to build a toolkit that can be used by non-programmers to "hook things together" given a rich set of programmer built libraries. It sounds like XML Configuration fits better here.
Joshua Starner