如何在Simple Injector中同时注册泛型IPollingService<TContext>以支持装饰与集合注入
解决方法(以Autofac为例)
1. 先确保泛型接口继承非泛型接口
这是核心前提——必须让IPollingService<TContext>继承自IPollingService,这样所有泛型服务的实现才能自动兼容非泛型的集合注入需求。如果你的接口还没这么定义,先调整:
public interface IPollingService { Task Poll(); } public interface IPollingService<TContext> : IPollingService { // 这里可以添加泛型特有的方法,比如 Task Poll(TContext context); }
2. 注册泛型服务的具体实现
假设你有多个泛型实现类(比如UserPollingService实现IPollingService<UserContext>、OrderPollingService实现IPollingService<OrderContext>),先把这些服务注册到容器:
// 注册具体泛型实现的方式 container.RegisterType<UserPollingService>() .As<IPollingService<UserContext>>() .InstancePerLifetimeScope(); container.RegisterType<OrderPollingService>() .As<IPollingService<OrderContext>>() .InstancePerLifetimeScope(); // 如果你的实现是开放泛型类(比如GenericPollingService<T>),可以这么注册 container.RegisterGeneric(typeof(GenericPollingService<>)) .As(typeof(IPollingService<>)) .InstancePerLifetimeScope();
3. 注册泛型装饰器
Autofac支持开放泛型的装饰器注册,直接针对IPollingService<>这个开放泛型接口,绑定你的ContextAwarePollingServiceDecorator<>:
// 这一步会自动把所有IPollingService<TContext>的实例,替换为被装饰后的版本 container.RegisterDecorator( typeof(IPollingService<>), typeof(ContextAwarePollingServiceDecorator<>));
4. 将装饰后的泛型服务映射到非泛型IPollingService
要让泛型服务能被纳入IPollingService集合,需要把每个IPollingService<TContext>的实例同时注册为非泛型的IPollingService,这里有两种灵活的方式:
方式一:注册时直接指定多接口
在注册具体泛型实现的时候,额外添加As<IPollingService>:
container.RegisterType<UserPollingService>() .As<IPollingService<UserContext>>() .As<IPollingService>() // 同时注册为非泛型接口 .InstancePerLifetimeScope();
方式二:用注册源统一处理(适合大量泛型实现的场景)
如果不想每个注册都手动加As<IPollingService>,可以自定义一个注册源,自动把所有IPollingService<TContext>的注册映射到非泛型接口:
public class PollingServiceRegistrationSource : IRegistrationSource { public IEnumerable<IComponentRegistration> RegistrationsFor( Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) { var typedService = service as TypedService; if (typedService?.ServiceType.IsGenericType == true && typedService.ServiceType.GetGenericTypeDefinition() == typeof(IPollingService<>)) { var nonGenericService = new TypedService(typeof(IPollingService)); foreach (var registration in registrationAccessor(service)) { yield return RegistrationBuilder.ForDelegate(nonGenericService, (context, parameters) => context.Resolve(service, parameters)) .As(nonGenericService) .InstancePerMatchingLifetimeScope(registration.Lifetime) .CreateRegistration(); } } } public bool IsAdapterForIndividualComponents => true; } // 把这个注册源加到容器里 container.AddRegistrationSource(new PollingServiceRegistrationSource());
5. 注册集合并注入到CompositePollingService
最后把所有IPollingService实现注册为集合,同时确保CompositePollingService的构造函数接受IEnumerable<IPollingService>参数:
// 收集所有需要加入集合的服务类型 var pollingServiceTypes = new List<Type> { typeof(UserPollingService), typeof(OrderPollingService), // 其他泛型/非泛型的IPollingService实现 }; // 注册集合 container.RegisterCollection(typeof(IPollingService), pollingServiceTypes); // 注册CompositePollingService(它的构造函数应该是:public CompositePollingService(IEnumerable<IPollingService> pollingServices)) container.RegisterType<CompositePollingService>().SingleInstance();
验证小技巧
- 可以在
ContextAwarePollingServiceDecorator的Poll方法里加日志,调用CompositePollingService.Poll()时,看是否触发了装饰器的逻辑,确认装饰器生效。 - 在
CompositePollingService的构造函数里遍历pollingServices,打印每个实例的类型,检查是否包含所有预期的服务。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

