Autofac选择基于父项依赖项的嵌套实现 [英] Autofac pick nested implementation based on parent dependency

查看:109
本文介绍了Autofac选择基于父项依赖项的嵌套实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出下面的示例依赖关系树,我想基于从容器中解析出的顶级依赖关系来选择底层的Config实例. TopLevelMessageConsumer将解析相同的IMessageService& IMessageQueue实现与TopLevelMessageDispatcher相同,但每个实现都有自己的Config实例.

Given the example dependency tree below I would like to select the bottom level Config instance based on the top level dependency being resolved from the container e.g. TopLevelMessageConsumer would resolve the same IMessageService & IMessageQueue implementations as TopLevelMessageDispatcher but each would have their own Config instance.

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

我知道可以使用KeyedNamed但这是可能的,但是这需要将树中的每个依赖项注册n次,具体次数取决于配置变化的数量.结果:

I know this is possible using Keyed or Named but this requires each dependency in the tree to be registered n times varying by the number of config variations. Resulting in:

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

是否有更好/更干净的方式注册它们?

Is there a better/cleaner way to register them?

推荐答案

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

You can simplify this greatly by using generic interfaces instead of explicit DI registration. The only condition is that you need to use some sort of type to differentiate between the services. In this case, making separate configuration classes would be a natural fit.

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

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

Note that the implementation of the services don't necessarily need to worry about the fact the type is generic - the only thing that needs to change is the constructor signature to make a more explicit call for the generic type.

这篇关于Autofac选择基于父项依赖项的嵌套实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆