¿Cómo descubrir el tipo de implementación subyacente de una instancia decorada al llamar a GetAllinstances?

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

Pregunta

Tengo este código:

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

instances es de tipo IEnumerable<IInstructionHandler<RenderWord>>

firstInstance es de tipo IInstructionHandler<RenderWord> Ese en realidad es una instancia de un decorador que decora otro decorador que decora otro decorador ...

En tiempo de ejecución la clase real instances es de tipo ContainerControlledCollection<IInstructionHandler<RenderWord>> y esto ContainerControlledCollection La clase tiene una información muy útil: la subyacente ImplementationType.

¿Hay alguna forma de llegar al ContainerControlledCollection o el producers[0].Value.ImplementationType en tiempo de ejecución porque realmente me gustaría poder descubrir el tipo de implementación base debajo de la cadena de decoradores.

¿Fue útil?

Solución

Creo que @atomaras podría tener un buen punto sobre su abstracción, aunque creo que estaría bien cuando solo use esta información dentro de su raíz de composición, ya que su raíz de composición ya está al tanto de cada implementación en el sistema.

Creo que hay algunas formas de llegar a esta información:

  1. Utilizar el DecoratorPredicateContext información que se suministra al RegisterDecorator Método de extensión:

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

    Puede hacer un registro falso que el inyector simple llamará para cada IInstructionHandler<T> en el sistema, pero evita que se aplique suministrando un predicado que siempre regresará false. Puede usar la información suministrada por un inyector simple en el DecoratorPredicateContext Para averiguar cuál es la implementación real del Type.

Alternativamente, puede inyectar un DecoratorContext instancia (v2.6 y arriba) en el más decorador (como se explicó aquí). los DecoratorContext contiene la misma información que el DecoratorPredicateContext lo hace, pero este objeto será inyectado automáticamente por un inyector simple en un decorador que depende. Le permite tomar la decisión dentro de un decorador, lo que podría ser muy conveniente en su caso.

  1. Agrega un IDecorator Abstracción al sistema para permitir atravesar la cadena del decorador.

    Dejando que cada decorador implementa un IDecorator interfaz que permite el acceso al decorado (tal como lo hizo aquí) Puede atravesar la cadena del decorador y encontrar el tipo de implementación 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;
            }
        }
    }
    

    Puede implementar sus decoradores con esta interfaz de la siguiente manera:

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

    Cuando implementó esta interfaz en todos sus decoradores, podrá hacer esto:

     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. Registre una lista de Registration instancias en uno de los RegisterAll sobrecargas, desde el Registration Object sabe sobre el tipo de implementación real.

  3. Pero en lugar del punto 3, también podría usar la lista de tipos de implementación que usó para crear esos registros:

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

    El inyector simple resolverá las implementaciones registradas siempre en el mismo orden que están registrados (esto está garantizado). Entonces, cuando resuelva una colección de cosas, ya tendrá la lista de implementaciones que se presentan en el mismo orden.

Otros consejos

¿Por qué no solo revisas el tipo de FirstInstance? ¿No le daría eso el tipo de implementación real? Sin embargo, debo decir que el hecho de que necesite saber el tipo de implementación es una buena indicación de problemas con su abstracción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top