Wie kann man den zugrunde liegenden Implementierungstyp einer dekorierten Instanz beim Aufrufen von GetAllinStances entdecken?

StackOverflow https://stackoverflow.com/questions/19825921

Frage

Ich habe diesen Code:

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

instances ist vom Typ IEnumerable<IInstructionHandler<RenderWord>>

firstInstance ist vom Typ IInstructionHandler<RenderWord> Das ist in Wirklichkeit eine Instanz eines Dekorateurs, der einen anderen Dekorateur dekoriert, der einen anderen Dekorateur dekoriert ...

Zur Laufzeit die eigentliche Klasse instances ist vom Typ ContainerControlledCollection<IInstructionHandler<RenderWord>> und das ContainerControlledCollection Die Klasse enthält eine sehr nützliche Information - die zugrunde liegende ImplementationType.

Gibt es eine Möglichkeit für mich, zum zu gelangen ContainerControlledCollection oder der producers[0].Value.ImplementationType zur Laufzeit, weil ich wirklich in der Lage sein möchte, den Basisimplementierungstyp unter der Kette der Dekorateure zu entdecken.

War es hilfreich?

Lösung

Ich denke, @atomaras hat vielleicht einen guten Punkt für Ihre Abstraktion, obwohl ich denke, dass es in Ordnung wäre, wenn Sie diese Informationen nur in Ihrer Kompositionsroste verwenden, da Ihre Kompositionswurzel bereits jede Implementierung im System kennen.

Ich denke, es gibt ein paar Möglichkeiten, um diese Informationen zu erreichen:

  1. Verwenden Sie das DecoratorPredicateContext Informationen, die an die geliefert werden RegisterDecorator Erweiterungsmethode:

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

    Sie können eine gefälschte Registrierung vornehmen, die einfache Injektor für jeden anruft IInstructionHandler<T> im System, aber Sie verhindern, dass es angewendet wird, indem Sie ein Prädikat liefern, das immer zurückkehrt false. Sie können die von einfachen Injektoren in der gelieferten Informationen verwenden DecoratorPredicateContext Um herauszufinden, was der tatsächliche Implementierungstyp ist.

Alternativ können Sie eine injizieren DecoratorContext Instanz (v2.6 und up) in den obersten Dekorateur (wie erklärt hier). Das DecoratorContext enthält die gleichen Informationen wie die DecoratorPredicateContext tut, aber dieses Objekt wird automatisch von einem einfachen Injektor in einen Dekorateur injiziert, von dem abhängig ist. Sie können die Entscheidung in einem Dekorateur treffen, was in Ihrem Fall möglicherweise sehr bequem ist.

  1. Füge ein an hinzu IDecorator Abstraktion zum System, um die Dekorateurkette zu durchqueren.

    Indem jeder Dekorateur a implementiert wird IDecorator Schnittstelle, die den Zugriff auf die Dekoration ermöglicht (genau wie getan hier) Sie können die Dekorationskette durchqueren und den tatsächlichen Implementierungstyp finden:

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

    Sie können Ihre Dekorateure mit dieser Oberfläche wie folgt implementieren:

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

    Wenn Sie diese Benutzeroberfläche für alle Ihre Dekorateure implementiert haben, können Sie dies tun:

     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. Registrieren Sie eine Liste von Registration Instanzen in einem der RegisterAll Überlastungen, seit der Registration Objekt kennt den tatsächlichen Implemedierungstyp.

  3. Anstelle von Punkt 3 können Sie auch die Liste der Implementierungstypen verwenden, mit denen Sie diese Registrierungen erstellt haben:

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

    Einfacher Injektor löst die registrierten Implementierungen immer in der gleichen Reihenfolge wie registriert (dies ist garantiert). Wenn Sie also eine Sammlung von Dingen lösen, haben Sie bereits die Liste der Implementierungen, die in derselben Reihenfolge festgelegt sind.

Andere Tipps

Warum überprüfen Sie nicht einfach die Art der Erstinstanz? Würde Ihnen das nicht den tatsächlichen Implementierungstyp geben? Ich muss jedoch sagen, dass die Tatsache, dass Sie wissen müssen, dass der Implementierungstyp ein guter Hinweis auf Probleme mit Ihrer Abstraktion ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top