You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:44:50