Maxime
Maxime

Reputation: 143

How can I inject two implementations as once with Unity?

I have a IConsole interface, describing how to write stuff to the console, and one implementation, upperCaseConsole.

IConsole is injected in the Foo class using Unity.

public interface IConsole {
 void WriteLine(string text);   
}

public class upperCaseConsole: IConsole {
    public void WriteLine(string text){
    Console.WriteLine(text.ToUpper());  
    }
}

public class Foo{
 private readonly IConsole console;
    public Foo(IConsole console){
    this.console = console; 
    }

    public void WriteStuff(string stuff){
    console.WriteLine(stuff);
    }
}

I would now like to change how the text is written to the console. I have done a good job decoupling the implementation from foo, and I can just inject a new implementation, say lowerCaseConsole instead.

public class lowerCaseConsole: IConsole {
    public void WriteLine(string text){
    Console.WriteLine(text.ToLower());  
    }
}

My problem is, despite my best tests, I am not really sure that lowerCaseConsole will do the job, and I would like to run both implementations simultaneously for a while.

How can I do it without duplicating all the code in Foo?

I would like to avoid something like:

public class Foo{
     private readonly IConsole lowerConsole;
     private readonly IConsole upperConsole;

        public Foo([Dependency("lower")] IConsole lowerConsole,
             [Dependency("upper")] IConsole upperConsole){
        this.lowerConsole = lowerConsole;
        this.upperConsole = upperConsole;   
        }

        public void WriteStuff(string stuff){
        lowerConsole.WriteLine(stuff);
        upperConsole.WriteLine(stuff);
        }
    }

Note: The real-life case is that I am about to move forward on a DB change. I would like to transparently start writing to the new DB, and see how things go, but keep writing to the current DB, just in case.

Upvotes: 2

Views: 55

Answers (2)

Johnny
Johnny

Reputation: 9529

You could use named registration to inject IEnumerable<IConsole>. This approach is easily extendable with more implementations...or you could easily remove one of them...

container.RegisterType<IConsole, LowerConsole>("LowerConsole");
container.RegisterType<IConsole, UpperConsole>("UpperConsole");
container.RegisterType<IEnumerable<IConsole>, IConsole[]>();

then the ctor of the Foo becomes a bit different and also the WriteStuff method...

public Foo(IEnumerable<IConsole> consoles)
{
    this.consoles = consoles; 
}

public void WriteStuff(string stuff)
{
    foreach(var console in consoles)
    {
        console.WriteLine(stuff);
    }
}

Upvotes: 1

Rufus L
Rufus L

Reputation: 37070

One option would be to create a third implementation that contains private members of the other two, and calls to it's WriteLine method would just be forwarded to both the other types.

public class BothCaseConsole : IConsole
{
    private readonly LowerCaseConsole lcc = new LowerCaseConsole();
    private readonly UpperCaseConsole ucc = new UpperCaseConsole();

    public void WriteLine(string text)
    {
        lcc.WriteLine(text);
        ucc.WriteLine(text);
    }
}

Then just inject this type into Foo:

new Foo(new BothCaseConsole()).WriteStuff("Stuff to write");

enter image description here

Upvotes: 4

Related Questions