鉴于下面的示例依赖关系树,我想基于从容器中解析的顶级依赖关系选择底层Config
实例,例如TopLevelMessageConsumer
会解析相同的IMessageService
& IMessageQueue
实施为TopLevelMessageDispatcher
,但每个实体都有自己的Config
实例。
- TopLevelMessageConsumer
- IMessageService
- IMessageQueue
- Config
- TopLevelMessageDispatcher
- IMessageService
- IMessageQueue
- Config
我知道使用Keyed
或Named
可以实现这一点,但这要求树中的每个依赖项的注册次数会因配置变量的数量而异。导致:
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));
是否有更好/更清洁的方式来注册它们?
答案 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>();
}
}
请注意,服务的实现不一定需要担心类型是通用的 - 唯一需要更改的是构造函数签名,以便对泛型类型进行更明确的调用。