Autofac 根据父依赖选择嵌套实现
Autofac pick nested implementation based on parent dependency
鉴于下面的示例依赖关系树,我想 select 底层 Config
实例基于从容器中解析的顶级依赖关系,例如TopLevelMessageConsumer
将解析与 TopLevelMessageDispatcher
相同的 IMessageService
和 IMessageQueue
实现,但每个实现都有自己的 Config
实例。
- TopLevelMessageConsumer
- IMessageService
- IMessageQueue
- Config
- TopLevelMessageDispatcher
- IMessageService
- IMessageQueue
- Config
我知道使用 Keyed
或 Named
是可能的,但这需要树中的每个依赖项根据配置变化的数量进行 n 次注册。结果:
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));
是否有 better/cleaner 注册方式?
您可以通过使用通用接口而不是显式 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>();
}
}
请注意,服务的实现不一定需要担心类型是通用的这一事实 - 唯一需要更改的是构造函数签名以更明确地调用通用类型。
鉴于下面的示例依赖关系树,我想 select 底层 Config
实例基于从容器中解析的顶级依赖关系,例如TopLevelMessageConsumer
将解析与 TopLevelMessageDispatcher
相同的 IMessageService
和 IMessageQueue
实现,但每个实现都有自己的 Config
实例。
- TopLevelMessageConsumer
- IMessageService
- IMessageQueue
- Config
- TopLevelMessageDispatcher
- IMessageService
- IMessageQueue
- Config
我知道使用 Keyed
或 Named
是可能的,但这需要树中的每个依赖项根据配置变化的数量进行 n 次注册。结果:
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));
是否有 better/cleaner 注册方式?
您可以通过使用通用接口而不是显式 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>();
}
}
请注意,服务的实现不一定需要担心类型是通用的这一事实 - 唯一需要更改的是构造函数签名以更明确地调用通用类型。