使用Scrutor注册开放泛型时构建ServiceProvider失败的原因分析
Scrutor泛型服务注册异常解析
一、原代码正常运行的原因
原代码的Scrutor扫描逻辑仅做了两件事:
- 筛选出所有可赋值给
IInterface<>的类,这里Concrete<TOther>因继承AbstractClass<string>(实现了IInterface<string>)被选中。 - 通过
.AsSelf()将类本身注册为服务。
此时DI容器只需要处理Concrete<TOther>这个开放泛型类型的注册——当后续请求Concrete<SomeSpecificType>时,容器可以通过传入具体的SomeSpecificType作为TOther的参数来实例化对象,完全符合泛型服务注册规则,因此运行正常。
二、取消注释后抛出ArgumentException的原因
取消注释的代码行是自定义服务类型映射:
.As(type => type.GetInterfaces().Where(v => v.IsGenericType && v.GetGenericArguments().Length == 1).ToArray())
它的作用是让Scrutor将类实现的所有单参数泛型接口都注册为服务。
对于Concrete<TOther>来说,它继承的AbstractClass<string>实现了IInterface<string>(封闭泛型接口,已指定类型参数为string)。这行代码会把IInterface<string>作为服务类型,Concrete<TOther>作为实现类型注册到容器中。
问题的核心矛盾:
IInterface<string>是封闭泛型服务(类型参数已固定)Concrete<TOther>是开放泛型实现(存在未绑定的类型参数TOther)
DI容器无法用开放泛型类型去实例化封闭泛型服务——当你请求IInterface<string>时,容器不知道该为TOther传入什么具体类型来创建Concrete<TOther>的实例,因此抛出异常:无法为服务类型“IInterface[System.String]”实例化实现类型“Concrete[TOther]”。
三、修复思路(可选)
如果想正确注册泛型接口,需要保证服务类型和实现类型的泛型参数匹配。比如:
- 调整实现类定义,让
Concrete<T>直接继承AbstractClass<T>,使泛型参数对应; - 或者修改接口筛选逻辑,排除掉那些类型参数不匹配的封闭泛型接口。
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

