2012-06-13 17 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