我有此代码:

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 允许访问装饰的接口(就像完成一样 这里)您可以穿越装饰链并找到实际实施类型:

    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