Как обнаружить основной тип реализации украшенного экземпляра при вызове GetallinStances?

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

Вопрос

У меня есть этот код:

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

instances имеет тип IEnumerable<IInstructionHandler<RenderWord>>

firstInstance имеет тип IInstructionHandler<RenderWord> На самом деле это пример декоратора, который украшает другой декоратор, который украшает еще один декоратор ...

Во время выполнения фактический класс instances имеет тип ContainerControlledCollection<IInstructionHandler<RenderWord>> и это ContainerControlledCollection Класс имеет очень полезную часть информации - базовая ImplementationType.

Есть ли у меня способ добраться до ContainerControlledCollection или producers[0].Value.ImplementationType во время выполнения, потому что я бы очень хотел бы открыть для себя тип реализации базового типа под цепочкой декораторов.

Это было полезно?

Решение

Я думаю, что @atomaras может иметь хороший момент в вашей абстракции, хотя я думаю, что было бы хорошо, когда вы используете эту информацию в корне композиции, поскольку ваш корень композиции уже знает о каждой реализации в системе.

Я думаю, что есть несколько способов добраться до этой информации:

  1. Использовать DecoratorPredicateContext информация, предоставленная RegisterDecorator Метод расширения:

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

    Вы можете сделать фальшивую регистрацию, которую простой инжектор позволит на каждый IInstructionHandler<T> в системе, но вы не позволяете его применению, предоставив предикат, который всегда вернется false. Анкет Вы можете использовать информацию, предоставленную простым инжектором в DecoratorPredicateContext Чтобы выяснить, что такое реализация.

В качестве альтернативы, вы можете ввести DecoratorContext экземпляр (v2.6 и выше) в максимальный декоратор (как объяснено здесь) А DecoratorContext содержит ту же информацию, что и DecoratorPredicateContext делает, но этот объект будет автоматически вводить простой инжектор в декоратор, который зависит от. Это позволяет вам принять решение внутри декоратора, что может быть очень удобно в вашем случае.

  1. Добавить IDecorator Абстракция в систему, чтобы позволить пересекать цепочку декоратора.

    Позволяя каждому декоратору внедрить IDecorator интерфейс, который допускает доступ к DecorateE (так же, как это сделано здесь) вы можете пройти через цепочку декоратора и найти фактический тип реализации:

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

    Вы можете реализовать свои декораторы с помощью этого интерфейса следующим образом:

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

    Когда вы реализовали этот интерфейс на всех ваших декораторах, вы сможете сделать это:

     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. Зарегистрировать список Registration экземпляры в одном из RegisterAll перегрузки, так как Registration Объект знает о фактическом типе реализации.

  3. Но вместо точки 3 вы можете также использовать список типов реализации, которые вы использовали для создания этих регистраций:

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

    Простой инжектор разрешит зарегистрированные реализации, всегда в том же порядке, что и зарегистрировано (это гарантировано). Поэтому, когда вы разрешаете коллекцию вещей, у вас уже будет список реализаций, которые выложены в том же порядке.

Другие советы

Почему бы вам просто не проверить тип первого инстановка? Разве это не даст вам фактический тип реализации? Я должен сказать, что тот факт, что вам нужно знать тип реализации, является хорошим признаком проблем с вашей абстракцией.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top