Como descobrir o tipo de implementação subjacente de uma instância decorada ao chamar GetallInstances?

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

Pergunta

Eu tenho este código:

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

instances é do tipo IEnumerable<IInstructionHandler<RenderWord>>

firstInstance é do tipo IInstructionHandler<RenderWord> Na realidade, é um exemplo de um decorador que decora outro decorador que decora outro decorador ...

Em tempo de execução da aula real instances é do tipo ContainerControlledCollection<IInstructionHandler<RenderWord>> e isto ContainerControlledCollection A classe possui uma informação muito útil - o subjacente ImplementationType.

Existe alguma maneira de eu chegar ao ContainerControlledCollection ou o producers[0].Value.ImplementationType Em tempo de execução, porque eu realmente gostaria de descobrir o tipo de implementação base sob a cadeia de decoradores.

Foi útil?

Solução

Eu acho que o @atomaras pode ter um bom ponto sobre sua abstração, embora eu ache que tudo ficaria bem quando você usa essas informações dentro da raiz da composição, pois sua raiz de composição já está ciente de todas as implementações do sistema.

Eu acho que existem algumas maneiras de chegar a essas informações:

  1. Use o DecoratorPredicateContext informações que são fornecidas ao RegisterDecorator Método de extensão:

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

    Você pode fazer um registro falso que o simples injetor exigirá para cada IInstructionHandler<T> No sistema, mas você evita que ele seja aplicado fornecendo um predicado que sempre retornará false. Você pode usar as informações fornecidas por injetor simples no DecoratorPredicateContext Para descobrir qual é o implementação real.

Como alternativa, você pode injetar um DecoratorContext instância (v2.6 ou mais) no topo mais decorador (conforme explicado aqui). o DecoratorContext contém a mesma informação que o DecoratorPredicateContext Faz, mas esse objeto será automaticamente injetado pelo injetor simples em um decorador que depende. Ele permite que você tome a decisão dentro de um decorador, o que pode ser muito conveniente no seu caso.

  1. Adicione um IDecorator Abstração no sistema para permitir atravessar a corrente do decorador.

    Permitindo que cada decorador implemente um IDecorator interface que permite o acesso ao decorado (exatamente como feito aqui) Você pode atravessar a corrente do decorador e encontrar o tipo de implementação real:

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

    Você pode implementar seus decoradores com esta interface da seguinte forma:

    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 você implementou essa interface em todos os seus decoradores, você poderá fazer isso:

     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. Registrar uma lista de Registration instâncias em um dos RegisterAll sobrecarga, já que o Registration Objeto conhece o tipo de implemenação real.

  3. Mas, em vez do ponto 3, você também pode usar a lista de tipos de implemenação que usou para criar esses registros:

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

    O Injetor Simples resolverá as implementações registradas sempre na mesma ordem em que estão registradas (isso é garantido). Portanto, quando você resolver uma coleção de coisas, você já terá a lista de implementações que são apresentadas na mesma ordem.

Outras dicas

Por que você não apenas verifica o tipo de FirstInstance? Isso não daria a você o tipo de implementação real? Devo dizer que o fato de você precisar saber que o tipo de implementação é uma boa indicação de problemas com sua abstração.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top