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

.NET 6中如何按服务类型条件注入依赖?

问题描述

我有一个基于.NET 6的C# gRPC解决方案(不确定gRPC属性是否对此问题有影响),包含两个实现不同gRPC服务逻辑的C#类,它们分别继承自两个不同proto文件中定义的服务基类:

public class MyServiceV2 : My_Service.My_ServiceBase
public class MyServiceV3 : My_Service_V3.My_Service_V3Base

这两个服务同时运行并已注册端点。

这两个类的构造函数均以ClassA作为参数,同时存在ClassA的派生类:

public class ClassAV2 : ClassA
public class ClassAV3 : ClassA

如何在启动文件中配置依赖注入(DI),使MyServiceV2的构造函数参数ClassA注入ClassAV2实例,MyServiceV3注入ClassAV3实例?

注:服务的构造函数参数不能直接使用具体派生类,因为不同环境有不同行为:生产环境按上述规则注入,非生产环境仅注入基类ClassA。我已能区分生产与非生产环境,仅需了解生产环境下针对特定服务的注入配置方式。

我期望实现的伪代码:

public void ConfigureServices(IServiceCollection services)
{
    if(InProduction()) //已实现此判断
    {
       services.FindService(typeof(MyServiceV2)).AddSingleton<ClassA, ClassAV2>();
       services.FindService(typeof(MyServiceV3)).AddSingleton<ClassA, ClassAV3>();
    }
    else
    {
       services.AddSingleton<ClassA>();
    }
}

解决方案

在.NET 6的DI系统中,要实现针对特定服务注入不同派生类实例,可以通过以下几种实用方式实现:

方法1:利用.NET 6+原生键控服务

.NET 6及以上版本支持键控服务,可给不同ClassA派生类打标识,注册gRPC服务时指定注入对应实例:

public void ConfigureServices(IServiceCollection services)
{
    if (InProduction())
    {
        // 注册带标识的ClassA派生类
        services.AddKeyedSingleton<ClassA, ClassAV2>("v2");
        services.AddKeyedSingleton<ClassA, ClassAV3>("v3");
        
        // 注册MyServiceV2并指定注入对应键的实例
        services.AddGrpc()
            .AddSingletonServiceProviderFactory<MyServiceV2>(sp => 
                new MyServiceV2(sp.GetRequiredKeyedService<ClassA>("v2")));
        
        // 注册MyServiceV3并指定注入对应键的实例
        services.AddGrpc()
            .AddSingletonServiceProviderFactory<MyServiceV3>(sp => 
                new MyServiceV3(sp.GetRequiredKeyedService<ClassA>("v3")));
    }
    else
    {
        services.AddSingleton<ClassA>();
        services.AddGrpc();
    }
}

方法2:手动实例化服务并传入构造参数

如果不想用键控服务,可直接在注册gRPC服务时手动创建实例,明确传入对应派生类:

public void ConfigureServices(IServiceCollection services)
{
    if (InProduction())
    {
        // 注册派生类实例
        services.AddSingleton<ClassAV2>();
        services.AddSingleton<ClassAV3>();
        
        // 手动注册MyServiceV2,传入ClassAV2
        services.AddSingleton<MyServiceV2>(sp => 
            new MyServiceV2(sp.GetRequiredService<ClassAV2>()));
        
        // 手动注册MyServiceV3,传入ClassAV3
        services.AddSingleton<MyServiceV3>(sp => 
            new MyServiceV3(sp.GetRequiredService<ClassAV3>()));
        
        services.AddGrpc();
    }
    else
    {
        services.AddSingleton<ClassA>();
        services.AddGrpc();
    }
}

方法3:工厂模式封装注入逻辑

如果需要更灵活的环境适配,可创建工厂类统一处理实例创建:

// 工厂类
public class ClassAFactory
{
    private readonly IServiceProvider _sp;
    private readonly bool _isProduction;

    public ClassAFactory(IServiceProvider sp)
    {
        _sp = sp;
        _isProduction = InProduction(); // 复用你已有的环境判断逻辑
    }

    public ClassA GetInstance(Type serviceType)
    {
        if (!_isProduction)
            return _sp.GetRequiredService<ClassA>();

        return serviceType switch
        {
            Type t when t == typeof(MyServiceV2) => _sp.GetRequiredService<ClassAV2>(),
            Type t when t == typeof(MyServiceV3) => _sp.GetRequiredService<ClassAV3>(),
            _ => _sp.GetRequiredService<ClassA>()
        };
    }
}

// 启动配置
public void ConfigureServices(IServiceCollection services)
{
    if (InProduction())
    {
        services.AddSingleton<ClassAV2>();
        services.AddSingleton<ClassAV3>();
    }
    services.AddSingleton<ClassA>();
    services.AddSingleton<ClassAFactory>();

    // 通过工厂注入对应实例
    services.AddSingleton<MyServiceV2>(sp => 
        new MyServiceV2(sp.GetRequiredService<ClassAFactory>().GetInstance(typeof(MyServiceV2))));
    services.AddSingleton<MyServiceV3>(sp => 
        new MyServiceV3(sp.GetRequiredService<ClassAFactory>().GetInstance(typeof(MyServiceV3))));

    services.AddGrpc();
}

注意事项

  • gRPC服务默认生命周期为单例,因此ClassA派生类也注册为单例可避免重复创建实例。
  • 上述方法均兼容MapGrpcService端点注册方式,DI会自动解析对应服务实例。

内容的提问来源于stack exchange,提问作者CodeMonkey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 03:04:59