Come scoprire il tipo di implementazione sottostante di un'istanza decorata quando si chiama GetAllinstances?

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

Domanda

Ho questo codice:

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

instances è di tipo IEnumerable<IInstructionHandler<RenderWord>>

firstInstance è di tipo IInstructionHandler<RenderWord> Questo in realtà è un esempio di un decoratore che decora un altro decoratore che decora un altro decoratore ...

In fase di esecuzione la classe effettiva instances è di tipo ContainerControlledCollection<IInstructionHandler<RenderWord>> e questo ContainerControlledCollection La classe contiene un'informazione molto utile: la sottostante ImplementationType.

C'è un modo per me di arrivare al ContainerControlledCollection o il producers[0].Value.ImplementationType In fase di esecuzione perché mi piacerebbe davvero essere in grado di scoprire il tipo di implementazione di base sotto la catena di decoratori.

È stato utile?

Soluzione

Penso che @atomaras potrebbe avere un buon punto sulla tua astrazione, anche se penso che andrebbe bene quando usi queste informazioni solo all'interno della radice della tua composizione, poiché la radice della composizione è già a conoscenza di ogni implementazione nel sistema.

Penso che ci siano alcuni modi per raggiungere queste informazioni:

  1. Utilizzare il DecoratorPredicateContext informazioni fornite al file RegisterDecorator Metodo di estensione:

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

    Puoi effettuare una falsa registrazione che il semplice iniettore richiederà ogni IInstructionHandler<T> Nel sistema, ma si impedisce che venga applicato fornendo un predicato che tornerà sempre false. È possibile utilizzare le informazioni fornite da un semplice iniettore in DecoratorPredicateContext Per scoprire qual è l'effettivo ImplementationType.

In alternativa, puoi iniettare un DecoratorContext istanza (v2.6 e su) nella parte superiore più decoratrice (come spiegato qui). Il DecoratorContext contiene le stesse informazioni del DecoratorPredicateContext fa, ma questo oggetto verrà automaticamente iniettato da un semplice iniettore in un decoratore da cui dipende. Ti consente di prendere la decisione all'interno di un decoratore, che potrebbe essere molto comodo nel tuo caso.

  1. Aggiungi un an IDecorator astrazione al sistema per consentire la attraversamento della catena del decoratore.

    Lasciando che ogni decoratore implementa un file IDecorator interfaccia che consente l'accesso al decorazione (proprio come fatto qui) puoi attraversare la catena del decoratore e trovare il tipo di implementazione effettivo:

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

    Puoi implementare i tuoi decoratori con questa interfaccia come segue:

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

    Quando hai implementato questa interfaccia su tutti i tuoi decoratori, sarai in grado di farlo:

     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. Registra un elenco di Registration istanze in uno dei RegisterAll sovraccarico, dal momento che Registration Oggetto è a conoscenza del tipo di implementazione effettivo.

  3. Ma invece del punto 3, potresti anche utilizzare l'elenco dei tipi di implementazione che hai usato per creare tali registrazioni:

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

    L'iniettore semplice risolverà le implementazioni registrate sempre nello stesso ordine in cui sono registrate (questo è garantito). Quindi, quando risolvi una raccolta di cose, avrai già l'elenco delle implementazioni che viene definita nello stesso ordine.

Altri suggerimenti

Perché non controlli semplicemente il tipo di prima installazione? Non ti darebbe il tipo di implementazione effettivo? Devo dire però che il fatto che devi conoscere il tipo di implementazione è una buona indicazione di problemi con la tua astrazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top