Castle Windsor - How to map Named instance in constructor injection

ktutnik picture ktutnik · Jul 4, 2012 · Viewed 7k times · Source

maybe this is easy, but searching it on the internet already give me a head ache

here is the problem:

interface IValidator
{
    void Validate(object obj);
}

public class ValidatorA : IValidator
{
    public void Validate(object obj) { }
}

public class ValidatorB : IValidator
{
    public void Validate(object obj) { }
}


interface IClassA { }
interface IClassB { }

public class MyBaseClass
{
    protected IValidator validator;

    public void Validate()
    {
        validator.Validate(this);
    }
}

public class ClassA : MyBaseClass, IClassA
{
    //problem: validator should ValidatorA
    public ClassA(IValidator validator) { }
}

public class ClassB : MyBaseClass, IClassB
{
    //problem: validator should ValidatorB
    public ClassB(IValidator validator) { }
}

public class OtherClass
{
    public OtherClass(IClassA a, IClassB b) { }
}


//on Main
var oc = container.Resolve<OtherClass>();

Any idea?

EDIT

I registered ValidatorA and ValidatorB with Named, now the problem how Castle Windsor can inject those validator properly to the ClassA and ClassB, is there a way to do that? or is there any better solution?

if there is someone think my class design is wrong please, i open for any advice. So far i think it correct. Yes, validator have specific configuration for specific Class. but there are reasons it is abstracted:

  1. Validator is a complex object, sometime should connect to database, so I MUST pass interface instead of implementation to constructor for unit testing reason.
  2. No way to use different interface for any of Validator, because the only method that i used is Validate
  3. I think MyBaseClass.Validate() a common template method pattern isn't it?

Answer

nemesv picture nemesv · Jul 4, 2012

Without going into the details of your chosen architecture just focusing on the Windsor container configuration:

If you have registered multiple named implementation to a given interface (IValidator), you can specify which one do you want to use when registering the consumer classes (ClassA, ClassB) with using ServiceOverrides:

The following container configuration providers an OtherClass with ClassA instance with a ValidatorA and ClassB instance with a ValidatorB:

var container = new WindsorContainer();

container.Register(Component.For<IClassA>().ImplementedBy<ClassA>()
    .DependsOn(ServiceOverride.ForKey<IValidator>().Eq("ValidatorA")));
container.Register(Component.For<IClassB>().ImplementedBy<ClassB>()
    .DependsOn(ServiceOverride.ForKey<IValidator>().Eq("ValidatorB")));

container.Register(Component.For<IValidator>().ImplementedBy<ValidatorA>()
    .Named("ValidatorA"));
container.Register(Component.For<IValidator>().ImplementedBy<ValidatorB>()
    .Named("ValidatorB"));

container.Register(Component.For<OtherClass>().ImplementedBy<OtherClass>());

var oc = container.Resolve<OtherClass>();