8

Here is the example:

interface IComponentA {};

class ComponentA : IComponentA { };

interface IComponentB { };

class ComponentB : IComponentB { };

interface IComponentC { };

class ComponentC : IComponentC
{
    public ComponentC(IComponentA a)
    {
        Console.WriteLine("Constructor A"); 
    }

    public ComponentC(IComponentB b) 
    {
        Console.WriteLine("Constructor B");
    }
};

All these components are registered in Castle Windsor container.

But class ComponentC has 2 overloaded constructors. Any of them can be used when ComponentC is being activated.

I need ComponentC(IComponentB b) constructor to be used.

For a moment I'm using UsingFactoryMethod() method to resolve that:

container
    .Register(Component
        .For<IComponentA>()
        .ImplementedBy<ComponentA>())
    .Register(Component
        .For<IComponentB>()
        .ImplementedBy<ComponentB>())
    .Register(Component
        .For<IComponentC>()
        .UsingFactoryMethod(() => new ComponentC(
            container.Resolve<IComponentB>())));

It works, but probably Castle Windsor provides some better way to do that?

Any help is really appreciated.

Thanks.

Alexander Stepaniuk
  • 6,217
  • 4
  • 31
  • 48
  • If it fits your model, you could try using the Typed Factory facility. I believe it will automatically pick the constructor that matches the parameters you pass in to the factory method. This means you'd have to have a factory and an instance of that type to pass in, tho. If you end up keeping your existing code, and if you're registering both in the same installer, and if `ComponentB` doesn't have dependencies, consider skipping the registration of `IComponentB`/`IComponentA` entirely. – Merlyn Morgan-Graham Oct 28 '11 at 08:21
  • [This question](http://stackoverflow.com/questions/784253/castle-windsor-passing-constructor-parameters) and some of the comments (e.g. `ISubDependencyResolver`) might also be useful. – Merlyn Morgan-Graham Oct 28 '11 at 08:27
  • Why does it matter which .ctor gets used? – Krzysztof Kozmic Oct 29 '11 at 03:46
  • @Krzysztof Koźmic E.g. Constructor `ComponentC(IComponentA)` creates `IComponentB` by itself and don't use `IComponentB` from container. `ComponentC(IComponentB)` creates `IComponentA` by itself and don't use `IComponentA` from container. As a result the behavior of `ComponentC` is different in these cases. – Alexander Stepaniuk Oct 29 '11 at 16:31
  • So let me see if I get this straight - you expose two dependencies, register them both in the container, but then want just one to be provided and manage the other manually? Then why expose it as a dependency at all? – Krzysztof Kozmic Oct 29 '11 at 22:51
  • @Krzysztof Koźmic. e.g. when `ComponentC` should be registered in container twice (with different IDs): 1) using ctor `ComponentC(IComponentA)` 2) using ctor `ComponentC(IComponentB)` – Alexander Stepaniuk Nov 20 '11 at 16:40
  • 1
    I'd say you might have two responsibilities in your class, perhaps you should split them? – Krzysztof Kozmic Nov 20 '11 at 21:39
  • @Krzysztof Koźmic Yes, that's one more way to solve it: Create new component that inherits `ComponentC` then this component will use required ctor for `ComponentC`. But I'd like to have syntax similar to `Register(Component.For().ImplementedBy() .UsingConstructor())` :) . Is there something similar in the Castle Windsor? – Alexander Stepaniuk Nov 21 '11 at 06:09
  • @AlexanderStepaniuk nope, nothing like that is provided, since it goes to unnecessary level of details. – Krzysztof Kozmic Sep 03 '12 at 21:22

2 Answers2

6

Windsor doesn't provide support for this scenario, because it breaks one of the unwritten assumptions it (and most containers) operates based on: "all constructors are created equal".

What that means, is that regardless of which constructor it choses there should be no functional differences in the behaviour of the component. All things being equal the more dependencies a component has the more capabilities it has, that's why Windsor will tend to pick greedier constructors first, but in case like yours I'd say either of two things are happening:

  • your component may actually be two components disguised as one. In that case you probably will want to split it.
  • your component actually does operate with both dependencies it has, and therefore it should have a single constructor that takes them both.

Another scenario I've seen is something like that:

public class Foo
{
   public Foo(ISession session){/*code*/}
   public Foo(ISessionFactory factory):this(factory.OpenSession()){}
}

While this might seem like a clever idea at first, at best it's superfluous, confusing and unnecessary. If your case looks like this one, I'd just remove the second constructor.

Krzysztof Kozmic
  • 27,267
  • 12
  • 73
  • 115
  • Good explanation. I'd agree with that. Thanks. – Alexander Stepaniuk Oct 13 '12 at 05:25
  • 2
    Your first bullet point took me to single responsibility principle of SOLID paradigm. Very impressive answer indeed! Your answer made my day and solved a mysterious windsor castle behavior my team-mate was observing. We are working on an ASP.net MVC project which has controllers with overloaded constructors and I was puzzled that how the heck the DI container is always calling the constructor with highest number of parameters. – RBT Mar 15 '16 at 01:01
1

Umm, it's awful but there is one way (I've had to do this with Linq2Sql DataContext objects in the past). You create a decorator class and register that instead.

Let's say you have this interface:

public interface IService 
{
    void DoSomething();
}

And you have an implementation as follows:

public class Service : IService
{
    private readonly ILogger _logger;

    public Service(ILogger logger)
        : this(logger, SomeDefaultListOfThings())
    {
    }

    // Let's say Windsor is calling this ctor for some reason (ArrayResolver?)
    public Service(ILogger logger, IEnumerable<object> emptyArrayFromWindsor)
    {
        _logger = logger;
        PutTheItemsSomewhere(emptyArrayFromWindsor);
    }

    public void DoSomething()
    {
        // Something that relies on the list of items...
    }
}

But as the example suggests, for some reason Windsor is calling the wrong ctor and you can't convince it otherwise (as Krzysztof correctly points out). Then you could create the decorator class as follows, which only has one constructor and thus removes the ambiguity:

public class SpecificCtorServiceDecorator : IService
{
    private readonly IService _decorated;

    public SpecificCtorServiceDecorator(ILogger logger)
    {
        _decorated = new Service(logger);
    }

    public void DoSomething()
    {
        _decorated.DoSomething();
    }
}

You'd then register that class instead:

container.Register(
    Component.For<IService>()
             .ImplementedBy<SpecificCtorServiceDecorator>());

Of course better would be to not have this weird default-values-in-other-constructors thing going on (search for "Poor-man's Dependency Injection"), but in the case where you're not in control of the class you actually want (like I was in Linq2Sql, or if it would be a breaking change to an API) then this might get you out of trouble.

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220