如何通过反射在Microsoft.Extensions.Hosting中注册泛型类型?
反射注册泛型服务的问题解决方法
问题根源
你当前的反射代码失败有两个核心原因:
- 泛型类型名称格式问题:泛型类/接口的
Name属性会带有`1后缀(比如Common<T>的Name是Common1,ICommon是ICommon1),你用$"I{name}"的匹配逻辑根本找不到对应的接口。 - 未区分开放泛型定义:注册泛型服务时,必须注册开放泛型类型(也就是
typeof(ICommon<>)这种不带具体类型参数的泛型定义),你的代码没做这个判断,直接注册会触发异常。
可行的反射注册实现
下面是修正后的代码,能正确识别并注册泛型服务,同时兼容非泛型服务的注册:
var types = assembly.GetTypes().Where(t => !t.IsInterface && !t.IsAbstract); foreach (var type in types) { Type interfaceType = null; // 处理泛型类 if (type.IsGenericTypeDefinition) { // 去掉名称里的泛型参数标记(`1`部分) var genericTypeName = type.Name.Split('`')[0]; // 匹配对应的泛型接口定义:接口是泛型定义,且名称为I+泛型类名 interfaceType = type.GetInterfaces() .Where(i => i.IsGenericTypeDefinition) .FirstOrDefault(i => i.Name.Split('`')[0] == $"I{genericTypeName}"); } // 处理非泛型类 else { var name = type.Name; interfaceType = type.GetInterfaces().FirstOrDefault(p => p.Name.Equals($"I{name}")); } if (interfaceType == null) { continue; } // 根据需求替换生命周期:Scoped/Singleton/Transient services.TryAddScoped(interfaceType, type); }
代码说明
- 通过
IsGenericTypeDefinition判断当前类型是否为泛型定义,分开处理泛型和非泛型逻辑。 - 对于泛型类型,分割名称中的
`符号去掉泛型参数标记,再匹配对应的I开头泛型接口。 - 注册时使用和手动注册一致的生命周期(示例用
TryAddScoped,可按需替换为其他生命周期)。
验证
用这段代码注册你的ICommon<T>和Common<T>,效果和手动写services.TryAddScoped(typeof(ICommon<>), typeof(Common<>))完全一致。
内容的提问来源于stack exchange,提问作者RongQing Zhang
相关产品推荐
相关产品推荐

