Autofac选择基于父依赖的嵌套实现

时间:2018-03-15 14:36:40

标签: c# .net dependency-injection inversion-of-control autofac

鉴于下面的示例依赖关系树,我想基于从容器中解析的顶级依赖关系选择底层Config实例,例如TopLevelMessageConsumer会解析相同的IMessageService& IMessageQueue实施为TopLevelMessageDispatcher,但每个实体都有自己的Config实例。

- TopLevelMessageConsumer
 - IMessageService
  - IMessageQueue
   - Config
- TopLevelMessageDispatcher
 - IMessageService
  - IMessageQueue
   - Config

我知道使用KeyedNamed可以实现这一点,但这要求树中的每个依赖项的注册次数会因配置变量的数量而异。导致:

containerBuilder.RegisterInstance(config1).Keyed<Config>(Key.One).SingleInstance();
containerBuilder.RegisterInstance(config2).Keyed<Config>(Key.Two).SingleInstance();

containerBuilder.RegisterType<MessageQueue>().Keyed<IMessageQueue>(Key.One).SingleInstance()
    .WithParameter(ResolvedParameter.ForKeyed<Config>(Key.One));
containerBuilder.RegisterType<MessageQueue>().Keyed<IMessageQueue>(Key.Two).SingleInstance()
    .WithParameter(ResolvedParameter.ForKeyed<Config>(Key.Two));

containerBuilder.RegisterType<MessageService>().Keyed<IMessageService>(Key.One).SingleInstance()
    .WithParameter(ResolvedParameter.ForKeyed<IMessageQueue>(Key.One));
containerBuilder.RegisterType<MessageService>().Keyed<IMessageService>(Key.Two).SingleInstance()
    .WithParameter(ResolvedParameter.ForKeyed<IMessageQueue>(Key.Two));

containerBuilder.RegisterType<TopLevelMessageConsumer>().AsSelf().SingleInstance()
    .WithParameter(ResolvedParameter.ForKeyed<IMessageService>(Key.One));
containerBuilder.RegisterType<TopLevelMessageDispatcher>().AsSelf().SingleInstance()
    .WithParameter(ResolvedParameter.ForKeyed<IMessageService>(Key.Two));

是否有更好/更清洁的方式来注册它们?

1 个答案:

答案 0 :(得分:1)

通过使用通用接口而不是显式DI注册,您可以大大简化这一过程。唯一的条件是您需要使用某种类型来区分服务。在这种情况下,制作单独的配置类是很自然的。

配置

public class ConsumerConfig : IConfig { }
public class DispatcherConfig : IConfig { }

接口

// Define interface of config here (you may opt for abstract class instead)
public interface IConfig { } 
public interface IMessageService<TConfig> { }
public interface IMessageQueue<TConfig> { }

服务

public class MessageService<TConfig> : IMessageService<TConfig> where TConfig : IConfig
{
    public MessageService(IMessageQueue<TConfig> messageQueue)
    {
    }
}

public class MessageQueue<TConfig> : IMessageQueue<TConfig> where TConfig : IConfig
{
    public MessageQueue(TConfig config)
    {
    }
}

public class TopLevelMessageDispatcher
{
    public TopLevelMessageDispatcher(IMessageService<DispatcherConfig> messageService)
    {
    }
}

public class TopLevelMessageConsumer
{
    public TopLevelMessageConsumer(IMessageService<ConsumerConfig> messageService)
    {
    }
}

用法

class Program
{
    static void Main(string[] args)
    {
        // Begin composition root
        var containerBuilder = new ContainerBuilder();

        var config1 = new ConsumerConfig();
        var config2 = new DispatcherConfig();

        containerBuilder.RegisterInstance(config1).AsSelf().SingleInstance();
        containerBuilder.RegisterInstance(config2).AsSelf().SingleInstance();

        containerBuilder.RegisterGeneric(typeof(MessageQueue<>))
            .As(typeof(IMessageQueue<>)).SingleInstance();
        containerBuilder.RegisterGeneric(typeof(MessageService<>))
            .As(typeof(IMessageService<>)).SingleInstance();
        containerBuilder.RegisterType<TopLevelMessageConsumer>()
            .AsSelf().SingleInstance();
        containerBuilder.RegisterType<TopLevelMessageDispatcher>()
            .AsSelf().SingleInstance();

        var container = containerBuilder.Build();
        // End composition root

        var dispatcher = container.Resolve<TopLevelMessageDispatcher>();
        var consumer = container.Resolve<TopLevelMessageConsumer>();
    }
}

请注意,服务的实现不一定需要担心类型是通用的 - 唯一需要更改的是构造函数签名,以便对泛型类型进行更明确的调用。