views:

219

answers:

2

I have following snippet:

static void Main(string[] args) {
    var container = new UnityContainer();
    container.RegisterType<IConnection, SerialPortConnection>("SerialConnection");
    container.RegisterType<IConnection, ParallelPortConnection>("ParallelConnection");
    container.RegisterType<Device>("ParallelDevice");
    container.RegisterType<Device>("SerialDevice");
}

I want to register type Device under two different names, so that depending on the name requested Device instance would be initialized with appropriate Connection. Following is one way to solve this, just for demonstration:

public class ParallelDevice : Device {
    public ParallelDevice([Dependency("ParallelConnection")] IConnection connection) : base(connection) {}
}
public class SerialDevice : Device {
    public SerialDevice([Dependency("ParallelConnection")] IConnection connection) : base(connection) {}
}

// and register with 
container.RegisterType<Device, ParallelDevice>("ParallelDevice");
container.RegisterType<Device, SerialDevice>("SerialDevice");

Is there a better way to do this? Something like:

container.RegisterType<Device>("ParallelDevice").UseDependencyNames("ParallelConnection");
+1  A: 

You can do it like this:

var container = new UnityContainer()
    .RegisterType<IConnection, SerialConnection>("SerialConnection")
    .RegisterType<Device, SerialDevice>(new InjectionConstructor(
        new ResolvedParameter<IConnection>("SerialConnection")));

or like this:

container
    .Configure<InjectedMembers>()
    .ConfigureInjectionFor<ParallelDevice>(new InjectionConstructor(
        new ResolvedParameter<IConnection>("ParallelConnection")));

This article has more examples as well as some extensions for Unity that allow you to write tests like this:

[Test]
public void Should_inject_named_instance_of_encryption_provider()
{
    var service = container.Resolve<MyService>();

    AssertNamedInstanceWasResolved<IEncryptionProvider>("MyEncryptionProvider");
}
Michael Valenty
+1  A: 

You should strive to keep your code free of DI Container-specifics. In this case, you can simply define your devices without referencing Unity at all. Here's the SerialDevice as an example, but the ParallelDevice class is entirely similar:

public class SerialDevice : Device
{
    public SerialDevice(IConnection connection)
        : base(connection) { }
}

You can configure your container like this:

container.RegisterType<IConnection, SerialPortConnection>("SerialConnection");
container.RegisterType<IConnection, ParallelPortConnection>("ParallelConnection");
container.RegisterType<Device, SerialDevice>("SerialDevice",
    new InjectionConstructor(new ResolvedParameter<IConnection>("SerialConnection")));
container.RegisterType<Device, ParallelDevice>("ParallelDevice",
    new InjectionConstructor(new ResolvedParameter<IConnection>("ParallelConnection")));

This will allow you to resolve both Device objects like this:

var serialDevice = container.Resolve<Device>("SerialDevice");
var parallelDevice = container.Resolve<Device>("ParallelDevice");
Mark Seemann