2

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

例如,如果我有以下片段......

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>() 

... 需要定义,但我正在为温莎人选择使用的术语(即 DependsOn 或 ServicesOverrides)和意图而苦苦挣扎。鉴于该方法称为“resolve”,我只能将传递给它的任何值用于解决使用哪个具体实现的决定。这个假设是错误的吗?

4

3 回答 3

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);
    }
}
于 2013-08-05T21:35:35.113 回答
2

我将这个真棒示例的答案授予 kellyb。在调查期间,使用 Castle.Windsor 3.2.1,我发现至少有 2 个在“resolve”方法中传递值的原因。

  1. 为了满足内在的类型依赖性,例如字符串,或者使用“Resolve”方法解析的对象中的整数——如 kellyb 的示例中所述。
  2. 帮助 Castle 确定选择哪个具体实现。

为了帮助说明这两种用途,我正在详细说明上面由 kellyb 提供的示例。

概要 - 或测试条件

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

接口 IFoo 定义

namespace CastleTest
{
    public interface IFoo
    {
    }
}

类 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”的具体实现被标记为默认值,则断言失败——也就是说,将 IFoo 解析为 Bar 不需要定义 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”方法中传递了一件事——实现的名称。

于 2013-08-06T17:51:40.387 回答
0

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

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

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

于 2013-08-05T10:30:48.927 回答