我正在授予kellyb这个杰出的例子的答案。在调查过程中,使用Castle.Windsor 3.2.1,我发现至少有两个在“解析”方法中传递值的原因。
- 为了满足本征型的依赖关系,例如字符串或整数在 通过使用“解析”方法的解析对象 - 如在kellyb的实施例中描述 。
- 帮助城堡识别选择哪个具体实现。
帮助说明两种用法我正在详细说明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);
}
}
}
类巴兹定义
namespace CastleTest
{
public class Baz
{
public override string ToString()
{
return "I am baz.";
}
}
}
测试(辊筒式,拜托了!)
kellyb的例子测试表明,如果没有提供ARGS期望一个失败的断言。 kellyb的例子没有注册多个实现。我的例子有多个实现注册,并根据哪些被标记为默认,这个断言可能会或可能不会失败。例如,如果名为“AFooNamedFoo”的具体实现标记为default,则assert成功完成 - 也就是说IFoo作为Foo的解析确实需要定义args。如果名为“AFooNamedBar”的具体实现标记为default,则断言失败 - 也就是说IFoo作为Bar的解析不需要定义参数,因为它对Baz的依赖关系已经被注册(在我的示例中,where多个具体的实现被注册)。出于这个原因,我已经在我的例子中评论了断言。
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对象的分辨率必须在“解决”的方法通过两件事情 - 在实现的名称,并作为额外的字符串依赖IDictionary对象。 Bar对象的解析有一件事在“解析”方法中传递 - 实现的名称。
您是否说过任何值已通过在解析方法中将用于满足正在解析的对象的构造函数参数?我发现在Castle Windsor 3中,传入的值有助于castle识别使用哪个具体实现(假设注册组件已经在名称方法中定义了一个值)。这与你的建议完全不同 - 并不是说你不正确,因为可能有多种用途。这是我试图确定的。您是否尝试过使用此提供的值来派生具体的实现? – barrypicker
字典,匿名类型和参数参数重载是我在上面显示的内容。 “key”参数重载用于解决按键指定注册。在最近版本的Windsor中,为注册分配一个密钥是可选的(如果每个服务类型有多个注册,密钥仍然是必需的)。重读你的问题后,你听起来像需要为注册指定一个键,然后在Resolve方法上传递一个键... – kellyb
或者使用像IHandlerSelector这样的东西来处理分辨率。这取决于你的架构和我的运行时知道哪些应该解决......但你应该尽可能避免从容器中“拉”。 – kellyb