Castle Windsor - How to map Named instance in constructor injection

谁都会走 提交于 2019-11-27 16:15:20

问题


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?

回答1:


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>();



回答2:


It appears that you're trying to put tight couples (ClassA with ValidatorA, ClassB with ValidatorB) as independent types into a common container. This is pointless. If you must rely on tight coupling like this, forget dependency injection in this regard and just hard-reference the types.

This would make more sense if you could implement a common validator for all classes. For instance, make the classes responsible for providing validation rules, and let Validator just enforce the rules. Or perhaps just include the whole validation inside your classes, which is probably the most sensible scenario here.

MyBaseClass.Validate() look like inversion of control, but not like a template method.



来源:https://stackoverflow.com/questions/11325699/castle-windsor-how-to-map-named-instance-in-constructor-injection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!