如何扫描实现泛型接口IProductRetriever<T>的类并注册?
扫描实现泛型接口的类并注册到DI容器的解决方案
问题背景
我负责管理不同类型产品,从各厂商API拉取产品信息。因为产品有通用属性,定义了泛型类Product<T>;为统一产品信息获取逻辑,创建了泛型接口IProductRetriever<TProductInfo>,各厂商对应的ProductRetriever类实现该接口,手动调用功能正常。
之前用非泛型接口时,能扫描程序集把ProductRetriever注册到DI容器,但改成泛型接口后,扫描代码里的x.GetInterface(nameof(IProductRetriever<>))部分报错,需要解决怎么扫描实现这个泛型接口的类并完成DI注册。
错误的筛选代码片段:
.Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterface(nameof(IProductRetriever<>)) == typeof(IProductRetriever<>))
问题原因
泛型接口的类型匹配不能直接用GetInterface加泛型名称的方式,因为GetInterface(nameof(IProductRetriever<>))返回的是构造好的泛型接口类型(比如IProductRetriever<SpecificInfo>),而typeof(IProductRetriever<>)是未构造的泛型接口定义,两者无法直接相等。
解决步骤
1. 修正筛选逻辑
修改代码,检查类是否实现了IProductRetriever<>的泛型定义:
.Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterfaces() .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProductRetriever<>)))
逻辑说明:
GetInterfaces()获取类实现的所有接口IsGenericType判断当前接口是否为泛型类型GetGenericTypeDefinition()提取泛型接口的原始定义(未构造的IProductRetriever<>),再和目标类型对比
2. 完成DI注册
筛选出符合条件的类后,为每个实现类匹配对应的泛型接口并注册:
var assembly = Assembly.GetExecutingAssembly(); // 可替换为指定要扫描的程序集 var retrieverTypes = assembly.GetTypes() .Where(x => x is { IsAbstract: false, IsClass: true } && x.GetInterfaces() .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProductRetriever<>))); foreach (var type in retrieverTypes) { // 获取类实现的IProductRetriever<>接口 var interfaceType = type.GetInterfaces() .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProductRetriever<>)); // 按需注册为瞬时/作用域/单例 services.AddTransient(interfaceType, type); }
3. 简化写法(可选)
如果使用第三方DI扩展库(如Scrutor、Autofac),可以更简洁完成扫描:
以Scrutor为例:
services.Scan(scan => scan .FromAssemblyOf<AnyProductRetriever>() // 指定包含实现类的程序集 .AddClasses(classes => classes.Where(type => type.GetInterfaces() .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IProductRetriever<>)))) .AsImplementedInterfaces() .WithTransientLifetime());
内容的提问来源于stack exchange,提问作者user20326571
相关产品推荐
相关产品推荐

