1

100個までの登録済みコンポーネント(ほとんどがシングルトン)を持つ既存のプロジェクトで、WindsorからStructuremapに切り替えようとしています。すべてのコンポーネントは、ロギングとヘルストラッキングを提供する共通の基本クラスを継承しているため、コンポーネントインスタンスを識別するために使用される「Name」プロパティが含まれています。

Windsorを使用すると、コンポーネントのNameプロパティを、コンポーネントをIOCコンテナに登録するために使用された名前に設定することができました(このためにファシリティを使用しました)。

私の質問: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

私の2番目に良いアプローチは、に解決される新しい「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 に答える