我将从具有约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)
,但我想知道是否可以避免将组件注册保持为“类似于结构图”
我错过了什么吗?
是的,'EnrichWith'真的看起来比'WithProperty'好 - 好点。 我的问题的核心是'context.RequestedName'不会返回被实例化的组件的名称,而是被请求的组件的名称。 – streuspeicher
我想要阻止的是我必须将“丰富”添加到100多个组件注册中,但是可能自定义扩展方法真的是这里要走的路。谢谢! – streuspeicher
是的,从这个角度来看,我认为扩展方法是一个很酷的解决方案 - 我可以帮助的只是实现该方法,不知道任何直接实现您的目标的东西。 – AlexCuse