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

C#/.NET Core中如何通过DI为同一类传参创建多实例

问题描述

我定义了如下接口:

public interface ITest
{
    void SayHello();
}

该接口的实现类代码如下:

public class Test : ITest
{
    Test(string type)
    {
        // Do Something with type
    }

    public void SayHello()
    {
        // 
    }
}

当前我在依赖注入容器中的注册方式为:

services.AddScoped<ITest, Test>();

我需要创建两个Test类实例,分别传入不同的构造参数,对应实例化逻辑如下:

Test t1 = new Test("ABC");
Test t2 = new Test("XYZ");

请问如何通过.NET Core的依赖注入机制实现上述需求?


解决方案

首先需要修正一个代码问题:你当前Test类的构造函数没有指定访问修饰符,默认为private,DI容器无法访问私有构造函数生成实例,需要先将构造函数改为public:

public Test(string type)
{
    // Do Something with type
}

你可以根据自己的使用场景选以下任意一种原生DI支持的实现方式:

方案1:直接注册多实例,通过集合注入

.NET Core原生DI支持同一服务类型注册多个实现,注入时解析IEnumerable<服务类型>即可拿到所有注册的实例,直接在注册时通过工厂委托传入构造参数即可:

// 注册传入"ABC"的实例
services.AddScoped<ITest>(sp => new Test("ABC"));
// 注册传入"XYZ"的实例
services.AddScoped<ITest>(sp => new Test("XYZ"));

使用时直接注入IEnumerable<ITest>,按注册顺序即可拿到两个目标实例:

public class BusinessService
{
    private readonly ITest _testAbc;
    private readonly ITest _testXyz;

    public BusinessService(IEnumerable<ITest> testInstances)
    {
        var testArray = testInstances.ToArray();
        _testAbc = testArray[0]; // 对应new Test("ABC")
        _testXyz = testArray[1]; // 对应new Test("XYZ")
    }
}

这种方式实现最简单,适合两个实例使用时不需要按名称区分、只需要按注册顺序获取的场景。Scoped生命周期下,同一个请求范围内获取到的两个实例都是固定的,符合生命周期规则。

方案2:封装工厂类,按需获取实例

如果不想靠注册顺序区分实例,可以自定义工厂封装实例创建逻辑,还可以借助ActivatorUtilities自动解析Test类的其他DI托管依赖,后续Test新增其他容器托管的构造参数时,不需要手动修改工厂创建逻辑:
首先定义工厂接口和实现:

public interface ITestFactory
{
    ITest GetByType(string type);
}

public class TestFactory : ITestFactory
{
    private readonly IServiceProvider _serviceProvider;

    // 工厂本身的依赖由DI容器自动注入
    public TestFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public ITest GetByType(string type)
    {
        return type switch
        {
            "ABC" => ActivatorUtilities.CreateInstance<Test>(_serviceProvider, "ABC"),
            "XYZ" => ActivatorUtilities.CreateInstance<Test>(_serviceProvider, "XYZ"),
            _ => throw new NotSupportedException($"不支持的类型参数: {type}")
        };
    }
}

注册工厂到DI容器:

services.AddScoped<ITestFactory, TestFactory>();

使用时直接注入工厂,按需获取对应实例即可:

public class BusinessService
{
    private readonly ITest _testAbc;
    private readonly ITest _testXyz;

    public BusinessService(ITestFactory testFactory)
    {
        _testAbc = testFactory.GetByType("ABC");
        _testXyz = testFactory.GetByType("XYZ");
    }
}

这种方式灵活性最高,后续新增其他type的实例只需要修改工厂的分支逻辑即可,不需要调整注册代码。

方案3:定义细分服务接口,直接注入对应实例

如果两个实例的业务职责完全隔离,也可以定义两个继承自ITest的子接口,分别对应不同参数的实现,注入时直接指定具体子接口类型即可,不需要靠顺序或工厂判断:

// 定义细分接口
public interface ITestAbc : ITest {}
public interface ITestXyz : ITest {}

// 对应实现类,调用基类构造函数传固定参数
public class TestAbc : Test, ITestAbc
{
    public TestAbc() : base("ABC") {}
}

public class TestXyz : Test, ITestXyz
{
    public TestXyz() : base("XYZ") {}
}

注册服务:

services.AddScoped<ITestAbc, TestAbc>();
services.AddScoped<ITestXyz, TestXyz>();

使用时直接注入对应子接口即可拿到目标实例:

public class BusinessService
{
    private readonly ITest _testAbc;
    private readonly ITest _testXyz;

    public BusinessService(ITestAbc testAbc, ITestXyz testXyz)
    {
        _testAbc = testAbc;
        _testXyz = testXyz;
    }
}

这种方式类型最安全,不需要做运行时的类型判断或顺序依赖,适合两个实例职责差异较大的场景,缺点是需要额外定义子接口和实现类。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:48:24