1

我即将从 Windsor 切换到 Structuremap 以用于现有项目,其中包含大约 100 个注册组件(主要是单例)。所有组件都继承自一个提供日志记录和健康跟踪的通用基类,因此,它包含一个用于标识组件实例的“名称”属性。

使用 Windsor,可以将组件的 Name 属性设置为用于在 IOC 容器中注册组件的名称(我们为此使用了 Facility)。

我的问题:Structuremap 可以做到这样吗?

(我梦想在某个地方接到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),但我想知道是否可以避免这种情况,以尽可能保持组件注册为“类似结构图”?

我错过了什么吗?

4

1 回答 1

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;
    });

这对于您的情况可能有点过分,但上下文意识可能非常有用。

于 2012-06-14T14:51:21.800 回答