1

私はこのコードを持っています:

using (container.BeginLifetimeScope())
{
    RenderWord instruction = new RenderWord();
    var instances = container.GetAllInstances<IInstructionHandler<RenderWord>>();
    var firstInstance = result.First();
}

instancesタイプですIEnumerable<IInstructionHandler<RenderWord>>

firstInstanceIInstructionHandler<RenderWord>実際には、別のデコレーターを装飾する別のデコレーターを装飾するデコレーターのインスタンスであるタイプです...

実行時の実際のクラスinstancesは 型ContainerControlledCollection<IInstructionHandler<RenderWord>>であり、このContainerControlledCollectionクラスは非常に有用な情報 (基になるImplementationType.

デコレータのチェーンの下にある基本実装タイプを発見できるようにしたいので、実行時にContainerControlledCollectionまたはに到達する方法はありますか。producers[0].Value.ImplementationType

4

2 に答える 2

2

@atomaras は抽象化について良い点があると思いますが、コンポジション ルートはシステム内のすべての実装を既に認識しているため、この情報をコンポジション ルート内でのみ使用する場合は問題ないと思います。

この情報にアクセスするには、いくつかの方法があると思います。

  1. 拡張メソッドDecoratorPredicateContextに提供される情報を使用します。RegisterDecorator

    var typeMapping = new Dictionary<Type, Type>();
    
    container.RegisterDecorator(typeof(IInstructionHandler<>), typeof(FakeDecorator<>), c =>
    {
        typeMapping[c.ServiceType]  = c.ImplementationType;
        // or perhaps even use c.AppliedDecorators property to see which decorators 
        // are applied.
    
        // return false to prevent the decorator from being applied.
        return false;
    });
    

    Simple Injector がシステム内のすべてに対して呼び出す偽の登録を行うことはできますが、IInstructionHandler<T>常に を返す述語を提供することで適用されないようにしますfalse。Simple Injector によって提供される情報を使用DecoratorPredicateContextして、実際の ImplementationType を確認できます。

DecoratorContextまたは、インスタンス (v2.6 以降) を最上位のデコレーターに挿入することもできます (ここで説明されているように)。にDecoratorContextは と同じ情報が含まれてDecoratorPredicateContextいますが、このオブジェクトは Simple Injector によって依存するデコレーターに自動的に注入されます。これにより、デコレーター内で決定を下すことができます。これは、あなたの場合には非常に便利です。

  1. システムに抽象化を追加してIDecorator、デコレータ チェーンをトラバースできるようにします。

    IDecorator各デコレータにデコレータへのアクセスを許可するインターフェイスを実装させることで (ここで行ったように)、デコレータ チェーンをトラバースして、実際の実装タイプを見つけることができます。

    public interface IDecorator
    {
        object Decoratee { get; }
    }
    
    public static class DecoratorHelpers
    {
        public static IEnumerable<object> GetDecoratorChain(IDecorator decorator)
        {
            while (decorator != null)
            {
                yield return decorator;
    
                decorator = decorator.Decoratee as IDecorator;
            }
        }
    }
    

    次のように、このインターフェースを使用してデコレーターを実装できます。

    public class SomeDecorator<T> : IInstructionHandler<T>, IDecorator
    {
        private readonly IInstructionHandler<T> decoratee;
    
        public SomeDecorator(IInstructionHandler<T> decoratee)
        {
            this.decoratee = decoratee;
        }
    
        object IDecorator.Decoratee { get { return this.decoratee; } }
    }
    

    このインターフェースをすべてのデコレーターに実装すると、次のことが可能になります。

     var implementationTypes =
         from handler in container.GetAllInstances<IInstructionHandler<RenderWord>>()
         let mostInnerDecorator =
             DecoratorHelpers.GetDecoratorChain(handler as IDecorator).LastOrDefault()
         let implementation = mostInnerDecorator != null ? mostInnerDecorator.Decoratee : handler
         select implementation.GetType()
    
  2. オブジェクトは実際の実装タイプを認識しているため、オーバーロードRegistrationの 1 つにインスタンスのリストを登録します。RegisterAllRegistration

  3. ただし、ポイント 3 の代わりに、これらの登録の作成に使用した実装タイプのリストを使用することもできます。

    typeMapping[serviceType] = implementationTypes;
    container.RegisterAll(serviceType, implementationTypes);
    

    Simple Injector は、登録された実装と常に同じ順序で解決します (これは保証されています)。したがって、物事のコレクションを解決すると、同じ順序で配置された実装のリストが既に得られます。

于 2013-11-07T09:10:00.210 に答える