2013-08-04 43 views
0

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

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

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

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

假设我已经IProcessor的两个具体实施方式 - 像处理器1:IProcessor,和/或Processor2:IProcessor。什么是'参数'用于?

我明白了...

Component.For<IProcessor>() 

...需要加以界定,但我与温莎人们选择使用的条款(即DependsOn,或ServicesOverrides)和意图挣扎。鉴于该方法被称为“解决方案”,我只能将任何传递给此值的图像用于解决关于使用哪个具体实现的决定。这个假设是错误的吗?

回答

2

您所讨论的参数参数是为Windsor组件无法满足的组件提供参数。匿名类型重载以及字典总体我相信都是为了这个目的。我过去曾经使用过这种方法,但我不推荐它,因为它会导致类似克里斯蒂亚诺提到的不良模式......而且上次我使用它时,它只适用于直接解决问题的组件。无论如何...这是一个例子,这是如何工作的:

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

您是否说过任何值已通过在解析方法中将用于满足正在解析的对象的构造函数参数?我发现在Castle Windsor 3中,传入的值有助于castle识别使用哪个具体实现(假设注册组件已经在名称方法中定义了一个值)。这与你的建议完全不同 - 并不是说​​你不正确,因为可能有多种用途。这是我试图确定的。您是否尝试过使用此提供的值来派生具体的实现? – barrypicker

+0

字典,匿名类型和参数参数重载是我在上面显示的内容。 “key”参数重载用于解决按键指定注册。在最近版本的Windsor中,为注册分配一个密钥是可选的(如果每个服务类型有多个注册,密钥仍然是必需的)。重读你的问题后,你听起来像需要为注册指定一个键,然后在Resolve方法上传递一个键... – kellyb

+0

或者使用像IHandlerSelector这样的东西来处理分辨率。这取决于你的架构和我的运行时知道哪些应该解决......但你应该尽可能避免从容器中“拉”。 – kellyb

0

实际上,您不应该在代码中调用Resolve,而应该在Composition root之前调用Resolve,并且您也不需要为Resolve方法提供参数。

定制的解决策略应该通过安装,工厂/ ITypedFactoryComponentSelector,subresolvers做......看到documentation,详细了解这些选项

BTW通过“Resolve”参数可以识别组件来解决(通过名称或类型)和它自己的直接依赖关系。

+0

是的,文件很轻。我有一种情况,具体implmentation具有基于接口的多个依赖关系 - 这些都具有基于接口的多个依赖关系。我还没有见过使用工厂方法的好**简单**示例。子解析器需要在方法'resolve'中返回时定义依赖关系链,这违背了DI容器的用途。我不知道,我可能接近完全错误。我使用DependsOn绊倒了一个真正有帮助的例子。根据运行时数据在组合根中调用Resolve – barrypicker

+0

关于工厂阅读此:http://docs.castleproject.org/Windsor.Typed-Factory-Facility-interface-based-factories.ashx – Crixo

2

我正在授予kellyb这个杰出的例子的答案。在调查过程中,使用Castle.Windsor 3.2.1,我发现至少有两个在“解析”方法中传递值的原因。

  1. 为了满足本征型的依赖关系,例如字符串或整数在 通过使用“解析”方法的解析对象 - 如在kellyb的实施例中描述 。
  2. 帮助城堡识别选择哪个具体实现。

帮助说明两种用法我正在详细说明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对象的解析有一件事在“解析”方法中传递 - 实现的名称。

相关问题