I have a constructor (AnimalHandler
) that takes two slightly different implementations of the same interface (IAnimal
). Using Simple Injector, how can I automatically decorate both implementations?
The chronology of an example:
interface IAnimal {
string Speak();
}
class Cat : IAnimal{
public string Speak() => "Meow";
}
class Dog : IAnimal{
public string Speak() => "Woof";
}
class AnimalSpeakLoudlyDecorator : IAnimal {
private readonly IAnimal _decorated;
public AnimalSpeakLoudlyDecorator(IAnimal decorated) {
_decorated = decorated;
}
public string Speak() => _decorated.Speak().ToUpper();
}
class AnimalHandler {
private readonly Cat _cat;
private readonly Dog _dog;
public AnimalHandler(Cat cat, Dog dog) {
_cat = cat;
_dog = dog;
}
public string HandleCat() => _cat.Speak();
public string HandleDog() => _dog.Speak();
}
Here I realize that interfaces should be used in the constructor so that decoration could occur. I thusly create AnimalInterfaceHandler
, ICat
, and IDog
:
interface ICat : IAnimal { }
interface IDog : IAnimal { }
class Cat : ICat {...}
class Dog : IDog {...}
class AnimalInterfaceHandler {
private readonly ICat _cat;
private readonly IDog _dog;
public AnimalInterfaceHandler(ICat cat, IDog dog) {
_cat = cat;
_dog = dog;
}
public string HandleCat() => _cat.Speak();
public string HandleDog() => _dog.Speak();
}
I register multiple interfaces with the same implementation.
var container = new Container();
var catRegistration = Lifestyle.Singleton.CreateRegistration<Cat>(container);
container.AddRegistration(typeof(ICat), catRegistration);
var dogRegistration = Lifestyle.Singleton.CreateRegistration<Dog>(container);
container.AddRegistration(typeof(IDog), dogRegistration);
container.RegisterCollection<IAnimal>(new[] { catRegistration, dogRegistration });
container.RegisterDecorator(typeof(IAnimal), typeof(AnimalSpeakLoudlyDecorator), Lifestyle.Singleton);
container.Verify();
var handler = container.GetInstance<AnimalInterfaceHandler>();
Assert.AreEqual("MEOW", handler.HandleCat());
The assert fails; the decorator is not applied despite being IAnimal
being registered with RegisterCollection
. Any ideas?
This should do the trick:
var container = new Container();
container.RegisterConditional<IAnimal, Cat>(c => c.Consumer.Target.Name == "cat");
container.RegisterConditional<IAnimal, Dog>(c => c.Consumer.Target.Name == "dog");
container.RegisterDecorator(typeof(IAnimal), typeof(AnimalSpeakLoudlyDecorator));
container.Verify();
This registration makes use of the RegisterConditional
method, which allows to make a conditional or contextual registration based on information about the consumer. In this case it uses the name of the constructor argument it is injected into.