You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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);
        }
    }
}

关键优化点

  1. 过滤可实例化类型:添加!t.IsInterface && !t.IsAbstract条件,确保只处理能被实例化的具体类,避免把接口作为实现类型注册。
  2. 修正Func类型:替换原有的Func<object>为强类型Func<TInterface>,通过表达式树生成正确的委托实例,保证类型匹配。
  3. 可选:仅处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 06:03:12