views:

158

answers:

2

Hi,

I'm new to Windsor, but I'm certain there must be a way to do this...

I have a class with three different constructors:

public MyClass(string SomeParam)
{
...
}

public MyClass(string AnotherParam, string YetAnother)
{
...
}

public MyClass(string AnotherOne, string YeahIKnow, string AnnoyingExampleParam)
{
...
}

In my external configuration file, I have my service defined as:

<component
  id="IMyClass"
  service="IMyInterface, MyAssembly"
  type="MyClass, MyOtherAssembly">

  <parameters>
    <AnotherOne>string value #1</AnotherOne>
    <YeahIKnow>string value #2</YeahIKnow>
    <AnnoyingExampleParam>string value #3</AnnoyingExampleParam>
  </parameters>

</component>

When Windsor initializes an instance of my class, it only wants to initialize using the first (single string parameter) constuctor of my class, when I really want Windsor to use the third constructor.

I don't see anything in the docs about forcing the kernel to us a particular constructor using an external configuration, even though I can find references to doing it in code, but that sort of defeats the purpose of an external configuration!

Any advice would be appreciated.

Best,

David Montgomery

A: 

What version of Castle? I recall, from the depths of what goes for my memory at 4am in the morning, that there was a resolution for constructor work in Castle 2.0.

Humm, memory coming back a little now... Something tells me that Castle will construct the object with the first public ctor. May be as simple as moving what you want for Castle to load, to the top.

If that doesn't work for you, perhaps refactor your code a little?

Option 1) Make the first two constructors internal.

Option 2) Use a Factory pattern for your complex objects, which will utilize castle on the backend to new up the more simple or complex version.

Option 3) Create 3 classes from your base superclass, each having a more complicated constructor. This way, you can specific in the Castle config file exactly which service to load. For example:

public abstract class BaseClass
{
  public BaseClass(String requiredParam)
  {
    ...
  }
}

public class SimpleClass : BaseClass
{
  public SimpleClass(String requiredParam, String anotherParam)
    : base(requiredParam)
  {
    ...
  }
}


public class MoreComplexClass : SimpleClass 
{
  public MoreComplexClass (String requiredParam, String anotherParam, String yetAnother)
    : base(requiredParam, anotherParam)
  {
    ...
  }
}

But, I myself have not run into this yet. Mainly because I stick to only public 1 ctor on my classes, with a few private/internal ctors for things such as Linq to new up my objects with an empty ctor (since Linq doesn't support Dependency Injection, boo).

Note that in that last statement, internal ctors, that my SRP (Single Responsiblity Pattern) for resolving my IoC components is external, in a seperate higharchy assembly (i.e. an application or UI layer). Since it not internal to my domain objects, the internal ctors are not seen by Castle.

eduncan911
Hi, I'm using 2.0. Changing my constructors via a wrapper class is working for me right now, though it feels like a bit of a dirty hack.
David Montgomery
Making a wrapper class just to get the right constructor is a dirty-hack, and not quite what I was going for. I was suggesting a seperation-of-concern by the 3 param ctor for a different class with different requirements. What about just moving the 3 param ctor to the top of the list?
eduncan911
I think the Factory pattern is definitely the right way to go (thanks for the tip BTW). Changing the order of constructors (or altering the constructors by adding a bogus parameter like I did) would rely on Castle's ctor 'scoring' mechanism to remain constant indefinitely -- which is an implementation detail I hope to soon forget about and never remember again!
David Montgomery
Are you using the Factory Pattern with Castle's Facility? Castle has the ability to call a "Create()" method on a dedicated class to new-up your object - instead of Castle just newing up the object and injecting the dependencies. If you are not, let me know - I'll modify the answer to show the pattern for Castle and Factory.
eduncan911
A: 

You must be doing something wrong.

Windsor uses the greediest constructor it can satisfy. If it uses the smaller one, you perhaps have some typo?

when your type is the service, you don't have to specify both

  service="MyClass, MyAssembly"
  type="MyClass">

remove the type.

Krzysztof Koźmic
Sorry, my example XML was bad. The above is correct as an example.
David Montgomery
I agree, that "I'm doing something wrong" is probably the issue at hand, but...the code found at http://fisheye2.atlassian.com/browse/castleproject/trunk/InversionOfControl/Castle.MicroKernel/ComponentActivator/DefaultComponentActivator.cs?r=5806#l204 seems to return the first single argument constructor as the appropriate constructor. I could be reading this quite wrong however. From my test, if I change the signature of my first constructor to have ANY second parameter, my configuration works as I would expect.
David Montgomery
no, it does not really work like this. It starts with the greediest constructor and goes down (WRT number of parameters) until it finds one it can satisfy. In your case it should start with the 3 parameter one and be able to use it. I'll have a look
Krzysztof Koźmic
Hi Krzysztof, I'm a bonehead. I was reading the Castle source 'if (Model.Constructors.Count == 1) ...' as if it meant 'Model.Parameters.Count == 1'. Please don't waste your time looking at the source just because I can't read!
David Montgomery

related questions