2012-06-13 16 views
1

我將從具有約100個註冊組件(大多數是單件)的現有項目的Windsor切換到結構映射。 所有組件都從提供日誌記錄和運行狀況跟蹤的公共基類繼承,因此包含用於標識組件實例的「Name」屬性。將註冊名稱綁定到結構映射中的組件實例

藉助Windsor,可以將組件的Name屬性設置爲用於在IOC容器中註冊組件的名稱(我們爲此使用了一個Facility)。

我的問題:這是可能的結構圖嗎?

(我夢想c.For<IFoo>.Use<Bar>.Named("Doe")通話奇蹟般地導致instanceOfBar.Name = "Doe"某處。)

這裏是我的嘗試:

using System; 
using StructureMap; 
using StructureMap.Interceptors; 
using System.Diagnostics; 

namespace ConsoleApplication1 
{ 
    interface IServiceA { } 

    interface IServiceB { } 

    class Base 
    { 
     public string Name { get; set; } 
    } 

    class ComponentA : Base, IServiceA { } 

    class ComponentB : Base, IServiceB 
    { 
     public ComponentB(IServiceA serviceA) 
     { 
      this.ServiceA = serviceA; 
     } 

     public IServiceA ServiceA { get; private set; } 
    } 

    class SetNameInterceptor : TypeInterceptor 
    { 
     public bool MatchesType(Type type) { return true; } 

     public object Process(object target, IContext context) 
     { 
      // *** Any other way? This does not work... 
      string name = context.BuildStack.Current != null ? context.BuildStack.Current.Name : context.RequestedName; 
      ((Base)target).Name = name; 
      return target; 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Container container = new Container(c => 
      { 
       c.RegisterInterceptor(new SetNameInterceptor()); 
       c.For<IServiceA>().Use<ComponentA>().Named("A"); 
       c.For<IServiceB>().Use<ComponentB>().Named("B"); 
      }); 

      var b = container.GetInstance<IServiceB>(); 

      // both Fail: 
      Debug.Assert(((ComponentB)b).Name == "B"); 
      Debug.Assert(((ComponentA)((ComponentB)b).ServiceA).Name == "A"); 
     } 
    } 
} 

以上顯然是行不通的,我試了變化,但有沒有運氣。目標對象的註冊名稱似乎不能通過IContext持續到達。

我的第二好辦法是定義一個新的「NamedComponent(...)」擴展方法,它解析爲Named(name).WithProperty(x => x.Name).EqualTo(name),但我想知道是否可以避免將組件註冊保持爲「類似於結構圖」

我錯過了什麼嗎?

回答

0

我從來沒有使用WithProperty之前,但如果它按我期望的方式工作應該爲你做的伎倆。

我想我會喜歡使用EnrichWith。喜歡的東西:

c.For<IFoo>().Use<Foo>().Named(name).EnrichWith(f => f.Name = name); 

EnrichWith有點更加明確它在做什麼IMO,並讓您返回給調用者之前調用您的實例的任何代碼。我喜歡這可以讓你做一個簡單的任務。

還有一個更復雜的處理程序,你可以用EnrichWith使用可以訪問請求的情況下 - 這將允許你做這樣的事情:

c.For<IFoo>().Use<Foo>().Named(name) 
    .EnrichWith((c, i) => { 
     i.Name = c.RequestedName; 
     return i; 
    }); 

這可能是矯枉過正您的具體情況但情景意識可能非常有用。

+0

是的,'EnrichWith'真的看起來比'WithProperty'好 - 好點。 我的問題的核心是'context.RequestedName'不會返回被實例化的組件的名稱,而是被請求的組件的名稱。 – streuspeicher

+0

我想要阻止的是我必須將「豐富」添加到100多個組件註冊中,但是可能自定義擴展方法真的是這裏要走的路。謝謝! – streuspeicher

+0

是的,從這個角度來看,我認爲擴展方法是一個很酷的解決方案 - 我可以幫助的只是實現該方法,不知道任何直接實現您的目標的東西。 – AlexCuse