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

如何在依赖注入中动态选择要使用的具体类

动态配置DI服务实现的方案

一、根据配置动态注册服务实现

你可以在构建ServiceCollection阶段直接读取配置,根据配置值选择对应的IOutputMaker实现进行注册,无需提前固定死实现类。

方式1:分支判断注册

直接读取配置中的输出类型,通过分支逻辑注册对应实现:

// 从配置中读取输出类型
var outputType = Program.configuration["OutputType"];

var services = new ServiceCollection()
    .AddSingleton<ISomething, Something>()
    .AddSingleton<IConfiguration>(Program.configuration);

// 根据配置动态添加IOutputMaker实现
switch (outputType)
{
    case "XML":
        services.AddSingleton<IOutputMaker, XMLOutputMaker>();
        break;
    case "XLSX":
        services.AddSingleton<IOutputMaker, ExcelOutputMaker>();
        break;
    default:
        // 可抛出异常或注册默认实现
        throw new InvalidOperationException($"不支持的输出类型:{outputType}");
}

var serviceProvider = services.BuildServiceProvider();

方式2:反射动态注册(扩展性更强)

如果需要新增输出类型时无需修改DI注册代码,可以在配置中指定实现类的全限定名,通过反射获取类型并注册:

var implTypeName = Program.configuration["OutputMakerImpl"];
var implType = Type.GetType(implTypeName);

if (implType == null || !typeof(IOutputMaker).IsAssignableFrom(implType))
{
    throw new InvalidOperationException("配置的输出类型无效");
}

var services = new ServiceCollection()
    .AddSingleton<ISomething, Something>()
    .AddSingleton<IConfiguration>(Program.configuration)
    .AddSingleton(typeof(IOutputMaker), implType);

var serviceProvider = services.BuildServiceProvider();

二、关于多次调用BuildServiceProvider

不建议多次调用BuildServiceProvider。每次调用都会创建一个全新的服务容器实例,容器内的单例服务会被重复实例化,既违背单例设计意图,也会造成资源浪费。

如果需要支持运行时动态切换输出类型(比如配置更新后无需重启),可以采用以下替代方案:

方案1:使用工厂模式

注册一个工厂类,由工厂根据当前配置创建对应的IOutputMaker实例:

// 定义工厂接口
public interface IOutputMakerFactory
{
    IOutputMaker GetOutputMaker();
}

// 实现工厂类
public class OutputMakerFactory : IOutputMakerFactory
{
    private readonly IConfiguration _config;
    private readonly IServiceProvider _serviceProvider;

    public OutputMakerFactory(IConfiguration config, IServiceProvider serviceProvider)
    {
        _config = config;
        _serviceProvider = serviceProvider;
    }

    public IOutputMaker GetOutputMaker()
    {
        var outputType = _config["OutputType"];
        return outputType switch
        {
            "XML" => _serviceProvider.GetRequiredService<XMLOutputMaker>(),
            "XLSX" => _serviceProvider.GetRequiredService<ExcelOutputMaker>(),
            _ => throw new InvalidOperationException($"不支持的输出类型:{outputType}")
        };
    }
}

注册时需要把所有可能的IOutputMaker实现都注册到容器:

var services = new ServiceCollection()
    .AddSingleton<ISomething, Something>()
    .AddSingleton<IConfiguration>(Program.configuration)
    .AddSingleton<XMLOutputMaker>()
    .AddSingleton<ExcelOutputMaker>()
    .AddSingleton<IOutputMakerFactory, OutputMakerFactory>();

var serviceProvider = services.BuildServiceProvider();

使用时通过工厂获取实例:

var factory = serviceProvider.GetRequiredService<IOutputMakerFactory>();
var outputMaker = factory.GetOutputMaker();

方案2:使用.NET 8+的键控服务(Keyed Service)

如果使用.NET 8及以上版本,可以利用键控服务给不同的IOutputMaker实现标记键,然后根据配置值获取对应键的服务:

var services = new ServiceCollection()
    .AddSingleton<ISomething, Something>()
    .AddSingleton<IConfiguration>(Program.configuration)
    // 给不同实现标记对应的键
    .AddKeyedSingleton<IOutputMaker, XMLOutputMaker>("XML")
    .AddKeyedSingleton<IOutputMaker, ExcelOutputMaker>("XLSX");

var serviceProvider = services.BuildServiceProvider();

// 使用时根据配置键获取服务
var outputType = Program.configuration["OutputType"];
var outputMaker = serviceProvider.GetRequiredKeyedService<IOutputMaker>(outputType);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:40:28