Castle Windsor Resolve方法:为什么传递参数?它们适用于什么?

时间:2013-08-04 22:26:21

标签: castle-windsor

我对Castle Windsor解决方法感到困惑。这种方法让我几乎可以传递任何东西。是否在resolve方法中提交的值传递并在最终解析为的对象的构造函数中使用,或者此值是否用于帮助解析器确定要使用的具体实现?

例如,如果我有以下代码段......

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

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

假设我有两个具体的IProcessor实现 - 比如Processor1:IProcessor和/或Processor2:IProcessor。什么是'参数'用于?

我理解......

Component.For<IProcessor>() 

...需要定义,但我正在努力解决Windsor人选择使用的术语(即DependsOn或ServicesOverrides)和意图。鉴于该方法被称为'resolve',我只能映像传递给它的任何值将用于解决决定使用哪个具体实现。这个假设是错的吗?

3 个答案:

答案 0 :(得分:4)

您正在讨论的arguments参数是为Windsor组件无法满足的组件提供参数。匿名类型重载以及我认为都是为此目的的字典工作服。我过去曾经使用过它,我不推荐它,因为它会导致像Cristiano提到的糟糕的模式......而上次我使用它时它只适用于直接解析的组件。无论如何......这是一个如何工作的例子:

[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);
    }
}

答案 1 :(得分:2)

我正在为凯利布的答案给出一个很棒的例子。在调查期间,使用Castle.Windsor 3.2.1,我发现在“resolve”方法中传递值至少有两个原因。

  1. 满足内部类型依赖关系,例如字符串或整数 通过使用“Resolve”方法解析对象 - 如 在kellyb的例子中描述。
  2. 帮助Castle确定要选择的具体实现。
  3. 帮助说明我正在详细阐述kellyb上面提供的示例的两种用法。

    概要 - 或测试条件

    假设有一个名为IFoo的接口和两个从这个接口派生的具体实现,称为Foo和Bar。定义了一个名为Baz的类,但不是从任何东西派生的。假设Foo需要两个字符串,但Bar需要一个Baz。

    接口IFoo定义

    namespace CastleTest
    {
        public interface IFoo
        {
        }
    }
    

    Class Foo定义

    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);
            }
        }
    }
    

    类别栏定义

    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);
            }
        }
    }
    

    班级Baz定义

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

    测试(鼓声,请!)

    kellyb的示例测试显示了一个断言,如果未提供args,则会发生故障。 kellyb的示例没有注册多个实现。我的示例已注册多个实现,并且根据哪个被标记为默认值,此断言可能会或可能不会失败。例如,如果名为“AFooNamedFoo”的具体实现被标记为默认,则断言成功完成 - 也就是说,IFoo作为Foo的分辨率确实需要定义args。如果名为“AFooNamedBar”的具体实现被标记为默认,则断言失败 - 也就是说,作为Bar的IFoo的分辨率不需要定义args,因为它已经注册了Baz的依赖性(在我的示例中注册了多个具体实现)。出于这个原因,我在我的例子中注释掉了断言。

    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."));
            }
        }
    }
    

    <强>结论

    查看上面的测试,Foo对象的解析在“resolve”方法中传递了两个东西 - 实现的名称,以及作为IDictionary对象的附加字符串依赖性。 Bar对象的解析在“resolve”方法中传递了一件事 - 实现的名称。

答案 2 :(得分:0)

事实上,您不应该在代码中而不是Composition root中调用Resolve,并且您也不应该在Resolve方法中提供参数。

自定义解决策略应该通过安装程序,工厂/ ITypedFactoryComponentSelector,子解析器完成...有关这些选项的更多详细信息,请参阅documentation

BTW到“Resolve”参数,您可以识别要解析的组件(按名称或类型)及其自身的直接依赖关系。