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對象的解析有一件事在「解析」方法中傳遞 - 實現的名稱。

相關問題