使用反射注册C#泛型类服务时遇实例化异常求助
错误原因
你注册服务时传入的type是未绑定类型参数的泛型定义类型(即DemoService1,对应代码里的DemoService)。DI容器无法直接实例化这种类型——因为它的泛型参数TDemo没有被具体的类型(比如某个符合class约束的具体类)替换,容器不知道该用什么类型填充TDemo,因此抛出ArgumentException`。
另外,你的反射代码中typeof(IDemo).IsAssignableFrom(t)可能存在逻辑问题:如果DemoService<TDemo>本身没有实现IDemo接口,而是TDemo实现了IDemo,那这个过滤条件会漏掉目标类型;如果DemoService<TDemo>确实实现了IDemo,那拿到的type就是泛型定义,这才会触发后续的错误注册逻辑。
可行解决方法
根据业务场景,有三种常见的处理方式:
1. 注册开放泛型服务(让DI自动匹配类型参数)
如果需要DI容器在注入时自动根据请求的具体类型填充TDemo,需要注册开放泛型的服务映射。前提是你的服务类型(比如BaseService)对应有泛型版本,或者你用泛型接口作为服务类型:
// 假设你有泛型基类BaseService<TDemo>,或者泛型接口IDemoService<TDemo> foreach (var type in types) { if (type.IsGenericTypeDefinition) { // 注册开放泛型:当请求BaseService<ConcreteType>时,容器会创建DemoService<ConcreteType>实例 services.AddScoped(typeof(BaseService<>), type); // 或者如果用接口:services.AddScoped(typeof(IDemoService<>), type); } }
如果BaseService是非泛型的,这种方式无法直接使用——因为容器无法推断出TDemo的具体类型,此时你需要调整服务设计,改用泛型服务类型。
2. 注册已绑定类型参数的具体泛型实现
如果你的程序集中存在DemoService的具体泛型实现(比如DemoService<Customer>、DemoService<Order>),需要过滤掉泛型定义,只处理已构造的泛型类型:
foreach (var type in types) { // 只处理已绑定了具体类型参数的泛型类型,跳过泛型定义 if (type.IsGenericType && !type.IsGenericTypeDefinition) { services.AddScoped(typeof(BaseService), type); } }
如果你的程序集中只有泛型定义,没有具体的泛型实现,那需要先手动绑定类型参数,再注册:
foreach (var type in types) { if (type.IsGenericTypeDefinition) { // 假设你要绑定的具体类型是ConcreteDemo(符合TDemo : class的约束) var concreteType = type.MakeGenericType(typeof(ConcreteDemo)); services.AddScoped(typeof(BaseService), concreteType); } }
3. 修正反射过滤逻辑(可选)
如果DemoService<TDemo>本身没有实现IDemo,而是TDemo实现了IDemo,那原来的反射过滤条件无法正确拿到目标类型,需要调整为:
var types = Assembly.Load("Come.Demo") .GetTypes() .Where(t => t.IsGenericTypeDefinition && typeof(IDemo).IsAssignableFrom(t.GetGenericArguments()[0])) .ToList();
内容的提问来源于stack exchange,提问作者Bushra Saifi

