.NET 8依赖注入:如何注册泛型接口IFoo<in T1, out T2>
.NET 8依赖注入中泛型接口IFoo<in T1, out T2>的注册问题解决
问题背景
在.NET 8应用中配置依赖注入,希望通过命名约定扫描程序集自动注册服务,但在处理泛型接口IFoo<in T1, out T2>时遇到问题——该接口的具体实现类继承自一个特定接口(此特定接口又继承自IFoo<,>)。
现有DI配置代码
public static void ConfigureServices(IServiceCollection services, Assembly assembly) { var types = assembly.GetTypes() .Where(t => t.GetInterfaces().Any(i => i.IsGenericType)).ToList(); foreach (var type in types) { var interfaces = type.GetInterfaces(); foreach (var @interface in interfaces) { // 注册接口到实现类的映射 services.AddTransient(@interface, type); // 注册Func工厂 services.AddTransient(typeof(Func<>).MakeGenericType(@interface), provider => new Func<object>(() => provider.GetService(@interface))); } } }
类结构示例
public interface ISpecificFoo : IFoo<Member, SpecificFoo.Output> { } public class SpecificFoo : ISpecificFoo { public class Output { } }
错误信息
System.ArgumentException: 无法为服务类型“IFoo`2”实例化实现类型“ISpecificFoo”
问题原因
原代码扫描逻辑未过滤接口类型,导致ISpecificFoo这个接口被当成实现类型,尝试注册给IFoo<Member, SpecificFoo.Output>——但接口本身无法实例化,因此抛出异常。此外,注册的Func<object>类型不匹配,无法正确返回目标接口实例。
解决方案
修改后的DI配置代码
public static void ConfigureServices(IServiceCollection services, Assembly assembly) { // 仅扫描可实例化的具体类:排除接口、抽象类 var types = assembly.GetTypes() .Where(t => !t.IsInterface && !t.IsAbstract && t.GetInterfaces().Any(i => i.IsGenericType)) .ToList(); foreach (var type in types) { var interfaces = type.GetInterfaces(); foreach (var @interface in interfaces) { // 注册接口与实现类的映射 services.AddTransient(@interface, type); // 注册对应类型的Func工厂,而非Func<object> var funcType = typeof(Func<>).MakeGenericType(@interface); // 通过表达式树创建强类型Func实例 var serviceProviderParam = Expression.Parameter(typeof(IServiceProvider)); var getServiceCall = Expression.Call( serviceProviderParam, nameof(IServiceProvider.GetService), new[] { @interface }); var lambda = Expression.Lambda(funcType, getServiceCall, serviceProviderParam); var funcInstance = lambda.Compile(); services.AddTransient(funcType, _ => funcInstance); } } }
关键优化点
- 过滤可实例化类型:添加
!t.IsInterface && !t.IsAbstract条件,确保只处理能被实例化的具体类,避免把接口作为实现类型注册。 - 修正Func类型:替换原有的
Func<object>为强类型Func<TInterface>,通过表达式树生成正确的委托实例,保证类型匹配。 - 可选:仅处理IFoo相关接口:如果只需要注册
IFoo<,>及其派生接口,可以在遍历接口时添加过滤条件:var isFooRelated = @interface.IsGenericType && @interface.GetGenericTypeDefinition() == typeof(IFoo<,>) || @interface.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IFoo<,>)); if (isFooRelated) { // 执行注册逻辑 }
内容的提问来源于stack exchange,提问作者JoxWar
相关产品推荐
相关产品推荐

