New Castle Windsor feature – typed arguments

With Windsor 2.1.1 out the door, we’re already working on version 3.0 (and looking for your feedback and ideas for the next version!). Yesterday I committed first “big” feature that probably will make it to the release.

DISCLAIMER:

All the code shown here represents a work in progress. Keep in mind that final version may be different. This also means that any feedback on this feature is appreciated.

Named Arguments

In current version of Windsor you can define inline dependencies for a component in at least three different ways:

  • When registering it (with value obtained at registration time):
    container.Register(

        Component.For<ICustomer>()

            .ImplementedBy<CustomerImpl>()

            .DependsOn(

                Property.ForKey("Name").Eq("Caption Hook"),

                Property.ForKey("Address").Eq("Fairyland"),

                Property.ForKey("Age").Eq(45)

                )

            );

  • When registering it (with value obtained at resolution time), AKA – Dynamic Parameters
    container.Register(

        Component.For<ClassWithArguments>()

            .LifeStyle.Transient

            .DynamicParameters((k, d) =>

            {

                d["timeStamp"] = DateTime.Now;

                d["user"] = Thread.CurrentPrincipal.Identity;

            })

        );

  • When resolving it (although this is something you should strive to avoid, using constructor injection and/or Typed factory facility)
  • var component = container.Resolve<ClassWithArguments>(new

    {

        TimeStamp = DateTime.Now,

        User = Thread.CurrentPrincipal.Identity

    });

What all these approaches have in common is that you specify dependency by name. Windsor when resolving the component will then use the value you provided for constructor arguments or settable properties with that name it finds on the component. What if you don’t care about the name?

Typed Arguments

Trunk version of Windsor lets you do just that – omit the name in which case Windsor will use the type of the argument as the sole information when building your component.

container.Register(

       Component.For<ClassWithArguments>()

           .Lifestyle.Transient

           .DependsOn(

              Property.ForKey<DateTime>().Eq(DateTime.Now),

              Property.ForKey<IIdentity>().Eq(Thread.CurrentPrincipal.Identity))

    );

As you can see here we use the type as the key for the dependency. This works also with dynamic parameters as well as when passing arguments straight from the call site. A new class – Arguments has been introduced to accommodate this new feature (although ordinal Hashtable or Dictionary<object,object> will do just fine as well) .

container.Resolve<ClassWithArguments>(

    new Arguments(new object[]

    {

        DateTime.Now,

        Thread.CurrentPrincipal.Identity

    })

);

The Arguments class itself implements IDictionary and can wrap either another IDictionary containing either named or typed arguments, anonymous type containing named arguments or array of objects to be used as typed arguments. It is advised to use this type when you plan to use typed arguments.

Additionally to help you deal with filling the dictionaries in more usable fashion an extension method on IDictionary (so they work for Arguments type as well) called Insert (with few overloads) has been introduced. It lets you insert arguments in a fluent, more user friendly fashion.

container.Register(

    Component.For<ClassWithArguments>()

    .DynamicParameters((k, d) =>

        d.Insert(DateTime.Now)

        .Insert(Thread.CurrentPrincipal.Identity))

    );

Final words

While this may be appealing at first to use typed arguments everywhere, resist the temptation unless you have a good reason. Named arguments should always be your first choice. Name is a valuable contextual information that may improve the readability of your code. Windsor will favor named arguments over typed and use the latter only if it can’t find a matching named argument.

Comments

Paul Cowan says:

Do you think this is a good idea to have all these different versions of windsor released so quickly together without any clear guidance of what the upgrade path is?

I am having serious doubts about using castle anymore because of the dependency mess it seems to produce in any project that uses it.

You guys can keep on slapping out different versions but what if I have a project that depends on castle 2.1.1 and then use another bit of OSS that is built on the latest version of windsor or a previous version?

I have to somehow rebuild all the castle.core etc. to the latest versions.

Then I have to get Nhibernate which is built against a different version of castle altogether.

Do you guys have no ideas about how to make this more managable??