Comment découvrir le type d'implémentation sous-jacent d'une instance décorée lors de l'appel de GetalLinstances?

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

Question

J'ai ce code:

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

instances est de type IEnumerable<IInstructionHandler<RenderWord>>

firstInstance est de type IInstructionHandler<RenderWord> C'est en réalité un exemple d'un décorateur qui décore un autre décorateur qui décore un autre décorateur ...

Au moment de l'exécution, la classe réelle instances est de type ContainerControlledCollection<IInstructionHandler<RenderWord>> et ça ContainerControlledCollection La classe détient une information très utile - le sous-jacent ImplementationType.

Y a-t-il un moyen pour moi d'arriver au ContainerControlledCollection ou la producers[0].Value.ImplementationType Au moment de l'exécution parce que j'aimerais vraiment pouvoir découvrir le type d'implémentation de base sous la chaîne de décorateurs.

Était-ce utile?

La solution

Je pense que @atomaras pourrait avoir un bon point sur votre abstraction, bien que je pense que ce serait bien lorsque vous n'utilisez ces informations que dans votre racine de composition, car votre racine de composition est déjà consciente de chaque implémentation du système.

Je pense qu'il y a plusieurs façons d'accéder à ces informations:

  1. Utilisez le DecoratorPredicateContext informations fournies au RegisterDecorator Méthode d'extension:

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

    Vous pouvez effectuer un faux enregistrement que l'injecteur simple appellera pour chaque IInstructionHandler<T> dans le système, mais vous empêchez son application en fournissant un prédicat qui reviendra toujours false. Vous pouvez utiliser les informations fournies par un simple injecteur dans le DecoratorPredicateContext Pour savoir quel est le Type d'implémentation réel.

Alternativement, vous pouvez injecter un DecoratorContext Instance (v2.6 et plus) dans le décorateur le plus haut (comme expliqué ici). La DecoratorContext contient les mêmes informations que le DecoratorPredicateContext Le fait, mais cet objet sera automatiquement injecté par un simple injecteur dans un décorateur qui dépend. Il vous permet de prendre la décision à l'intérieur d'un décorateur, ce qui pourrait être très pratique dans votre cas.

  1. Ajouter un IDecorator Abstraction au système pour permettre la traversée de la chaîne de décorateur.

    En laissant chaque décorateur mettre en œuvre un IDecorator interface qui permet d'accéder au décoré (tout comme fait ici) Vous pouvez traverser la chaîne de décorateur et trouver le type de mise en œuvre réel:

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

    Vous pouvez implémenter vos décorateurs avec cette interface comme suit:

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

    Lorsque vous avez mis en œuvre cette interface sur tous vos décorateurs, vous pourrez le faire:

     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. Enregistrer une liste de Registration instances dans l'un des RegisterAll surcharge, puisque le Registration L'objet connaît le type d'imprégération réel.

  3. Mais au lieu du point 3, vous pourriez aussi bien utiliser la liste des types de mise en œuvre que vous avez utilisés pour créer ces enregistrements:

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

    L'injecteur simple résoudra toujours les implémentations enregistrées dans le même ordre qu'elles sont enregistrées (ceci est garanti). Ainsi, lorsque vous résolvez une collection de choses, vous aurez déjà la liste des implémentations qui est présentée dans le même ordre.

Autres conseils

Pourquoi ne vérifiez-vous pas simplement le type de FirstInstance? Cela ne vous donnerait-il pas le type de mise en œuvre réel? Je dois dire cependant que le fait que vous devez connaître le type d'implémentation est une bonne indication des problèmes avec votre abstraction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top