2
votes

I am confused by Castle Windsor resolve method. This method allows me to pass almost anything. Is the value submitted in the resolve method passed along and used in the constructor of the object which is eventually resolved to, or is this value used to help the resolver determine what concrete implementation to use?

For example, if I have the following snippet...

var _container = new WindsorContainer();
_container.Install(FromAssembly.This());

var MyProcessor = _container.Resolve<IProcessor>(new Arguments(new {"Processor1"}));

assuming I have two concrete implementations of IProcessor - like Processor1:IProcessor, and/or Processor2:IProcessor. What are the 'Arguments' used for?

I understand the...

Component.For<IProcessor>() 

... needs to be defined, but I am struggling with the terms the Windsor folks choose to use (i.e. DependsOn, or ServicesOverrides) and the intent. Given the method is called 'resolve' I can only image any values passed to this will be used to resolve the decision on which concrete implementation to use. Is this assumption wrong?

3

3 Answers

4
votes

The arguments parameter you're talking about is for providing arguments to components that can't be satisfied by Windsor components. The anonymous types overloads as well as the dictionary overalls I believe are all for this purpose. I've used this in the past, and I don't recommend it as it leads to poor patterns like Cristiano mentioned... and last time I used this it only works for the component being directly resolved. Anyway... here's an example of how this works:

[TestFixture]
public class Fixture
{
    [Test]
    public void Test()
    {
        IWindsorContainer container = new WindsorContainer();
        container.Register(Component.For<IFoo>().ImplementedBy<Foo>().LifeStyle.Is(LifestyleType.Transient));

        Assert.Throws<HandlerException>(() => container.Resolve<IFoo>());

        IFoo foo = container.Resolve<IFoo>(new {arg1 = "hello", arg2 = "world"});
        Assert.That(foo, Is.InstanceOf<Foo>());
        Assert.That(foo.ToString(), Is.EqualTo("hello world"));
    }
}

public interface IFoo
{

}

public class Foo : IFoo
{
    private readonly string _arg1;
    private readonly string _arg2;

    public Foo(string arg1, string arg2)
    {
        _arg1 = arg1;
        _arg2 = arg2;
    }

    public override string ToString()
    {
        return string.Format("{0} {1}", _arg1, _arg2);
    }
}
2
votes

I am awarding the answer to kellyb for the awesome example. During investigation, using Castle.Windsor 3.2.1, I found at least 2 reasons for passing a value in the "resolve" method.

  1. To satisfy intrinsic type dependencies, such as strings, or integers in the object resolved by the use of the "Resolve" method - as described in kellyb's example.
  2. To help Castle identify which concrete implementation to select.

to help illustrate both uses I am elaborating on the example provided above by kellyb.

Synopsis - or test condition

Assume there is one interface called IFoo and two concrete implementations that derive from this interface called Foo and Bar. A class called Baz is defined but does not derive from anything. Assume Foo requires two strings, but Bar requires a Baz.

Interface IFoo Definition

namespace CastleTest
{
    public interface IFoo
    {
    }
}

Class Foo Definition

namespace CastleTest
{
    public class Foo : IFoo
    {
        private readonly string _arg1;
        private readonly string _arg2;

        public Foo(string arg1, string arg2)
        {
            _arg1 = arg1;
            _arg2 = arg2;
        }

        public override string ToString()
        {
            return string.Format("{0} {1}", _arg1, _arg2);
        }
    }
}

Class Bar Definition

namespace CastleTest
{
    class Bar : IFoo
    {
        private Baz baz;

        public Bar(Baz baz)
        {
            this.baz = baz;
        }

        public override string ToString()
        {
            return string.Format("I am Bar.  Baz = {0}", baz);
        }
    }
}

Class Baz Definition

namespace CastleTest
{
    public class Baz
    {
        public override string ToString()
        {
            return "I am baz.";
        }
    }
}

The Test (Drum roll, please!)

kellyb's example test shows an assert that expects a failure if args is not supplied. kellyb's example does not have multiple implementations registered. My example has multiple implementations registered, and depending on which is marked as the default this assert may or may not fail. For example, if the concrete implementation named "AFooNamedFoo" is marked as default, the assert completes successfully - that is to say the resolution of an IFoo as a Foo does indeed require args to be defined. If the concrete implementation named "AFooNamedBar" is marked as default, the assertion fails - that is to say the resolution of an IFoo as a Bar does not require args to be defined because its dependency of a Baz is already registered (in my example where multiple concrete implementations are registered). For this reason, I have commented out the assert in my example.

using Castle.Core;
using Castle.MicroKernel.Handlers;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using NUnit.Framework;

namespace CastleTest
{
    [TestFixture]
    public class ArgsIdentifyConcreteImplementation
    {
        [Test]
        public void WhenSendingArgsInResolveMethodTheyAreUsedToIdentifyConcreteImplementation()
        {
            IWindsorContainer container = new WindsorContainer();
            container.Register(Component.For<IFoo>().ImplementedBy<Foo>().LifeStyle.Is(LifestyleType.Transient).Named("AFooNamedFoo"));
            container.Register(Component.For<IFoo>().ImplementedBy<Bar>().LifeStyle.Is(LifestyleType.Transient).Named("AFooNamedBar").IsDefault());
            container.Register(Component.For<Baz>().ImplementedBy<Baz>().LifeStyle.Is(LifestyleType.Transient));

            // THIS ASSERT FAILS IF AFooNamedBar IS DEFAULT, BUT
            // WORKS IF AFooNamedFoo IS DEFAULT
            //Assert.Throws<HandlerException>(() => container.Resolve<IFoo>());

            // RESOLVE A FOO
            IFoo foo = container.Resolve<IFoo>("AFooNamedFoo", new { arg1 = "hello", arg2 = "world" });
            Assert.That(foo, Is.InstanceOf<Foo>());
            Assert.That(foo.ToString(), Is.EqualTo("hello world"));

            // RESOLVE A BAR
            IFoo bar = container.Resolve<IFoo>("AFooNamedBar");
            Assert.That(bar, Is.InstanceOf<Bar>());
            Assert.That(bar.ToString(), Is.EqualTo("I am Bar.  Baz = I am baz."));
        }
    }
}

Conclusion

Looking at the test above, the resolution of a Foo object has two things passed in the "resolve" method - the name of the implementation, and the additional string dependencies as an IDictionary object. The resolution of a Bar object has one thing passed in the "resolve" method - the name of the implementation.

0
votes

In fact you should not call Resolve ever in your code rather than in the Composition root and also there you should not need to supply parameters to the Resolve method.

Custom resolution strategies should be done through installers, factories/ITypedFactoryComponentSelector, subresolvers... see documentation for more details on those options

BTW through "Resolve" parameters you can identify the component to resolve(by name or type) and its own direct dependencies.