简体   繁体   中英

Castle Windsor IoC Container Instantiation for multiple concrete types

I am new to IoC and Castle Windsor.

The question is more related to IoC, but i just chose Castle as my weapon of choice.

I immediately ran into a problem that it seems impossible to construct the container from a config file or from a singleton.

The only way seeming to work for me is to use a Builder function that will construct the whole container each time and then let me specify the types, look at this example:

I have a view:

public interface IView
{
}

There are 2 concrete implementations of this view:

public class ConcreteViewA : IView
{
}

public class ConcreteViewB : IView
{
}

I have a controller that operates on the view:

public class Controller
{
    public Controller(IView view) { }
    public void Load() { }
}

I create a function that constructs my IoC container and register the common types, the only type i can register is my controller, as this is all that stays the same:

WindsorContainer BuildContainer()
    {
        var container = new WindsorContainer();
        container.Register(Component.For<Controller>().ImplementedBy<Controller>());
        return container;
    }

I have 2 (Root) entry points:

void RootMethod1()
    {
        var container = BuildContainer();
        container.Register(Component.For<IView>().ImplementedBy<ConcreteViewA>());
        var controller = container.Resolve<Controller>();
        controller.Load();
    }

    void RootMethod2()
    {
        var container = BuildContainer();
        container.Register(Component.For<IView>().ImplementedBy<ConcreteViewB>());
        var controller = container.Resolve<Controller>();
        controller.Load();
    }

As you can see I have to rebuild the container each time as i need to tell it what to use for IView for each of the context i am in. What if the Container is expensive to rebuild (Lots of types etc), how can I design this?

From what I understand, you need two different instances of the Controller class (each one constructed with a different IView type). The easiest way to achieve this is to register two components with different names and different dependencies.

WindsorContainer BuildContainer()
{
    var container = new WindsorContainer();

        container.Register(Component.For<Controller>().Named("ControllerWithViewA")
                                                      .ImplementedBy<Controller>()
                                                      .DependsOn(Property.ForKey(typeof(IView))
                                                      .Is(typeof(ConcreteViewA)));
        container.Register(Component.For<Controller>().Named("ControllerWithViewB")
                                                     .ImplementedBy<Controller>()
                                                     .DependsOn(Property.ForKey(typeof(IView))
                                                     .Is(typeof(ConcreteViewB)));
    return container;
}

You can then ask for any controller as and when required.

void RootMethod1()
{
    var container = BuildContainer();
    var controller = container.Resolve<Controller>("ControllerWithViewA");
    controller.Load();
}

void RootMethod2()
{
   var controller = container.Resolve<Controller>("ControllerWithViewB");
   controller.Load();
}

A few more things to keep in mind when using DI

  1. Build your container only once (Building it again and again is a waste of time and resources).

  2. Be very sure which dependencies to inject and which not to. Overusing DI for everything can result in a bloated container which is a maintenance nightmare.

  3. Be informed about the life cycle of your components (Singleton, Transient, per thread etc). Especially with Castle the default lifestyle is singleton which might create inconsistent behavior in a multi-threaded scenario.

You could look at using a handler selector. This would allow you to dynamically choose which view to resolve based on whatever code you choose. See here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM