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

请教:我对Microsoft.Extensions.DependencyInjection的使用理解是否正确?

关于Microsoft.Extensions.DependencyInjection的使用理解修正与说明

你的核心思路是对的——用DI框架统一注入默认SqlConnection来减少重复样板代码,确实能解决30个类都要手动传默认连接的麻烦。但代码里有几个细节问题需要调整才能正常工作,具体如下:

1. SqlConnection注册的语法错误

你写的services.AddTransient<SqlConnection, MySensibleDefaultSqlConnection()>();是错误的,正确的注册方式分两种情况:

  • 如果MySensibleDefaultSqlConnection是SqlConnection的子类,直接注册类型即可:
    services.AddTransient<SqlConnection, MySensibleDefaultSqlConnection>();
    
  • 如果MySensibleDefaultSqlConnection是一个创建SqlConnection的方法(比如静态工厂),用工厂委托注册:
    services.AddTransient<SqlConnection>(_ => MySensibleDefaultSqlConnection());
    

2. 混合参数的传递问题

ServiceProvider.GetRequiredService<SqlClass1>("foo")这种写法行不通,因为MSDI的GetRequiredService不支持直接传递构造函数的非注入参数。针对这种既有注入依赖(SqlConnection)又有动态参数(比如UserName)的场景,推荐两种解决方案:

方案一:使用ActivatorUtilities.CreateInstance

这个工具类可以结合DI容器中的服务和手动传入的参数来创建实例,正好匹配你的需求:

// 替代原来的GetRequiredService调用
var x = ActivatorUtilities.CreateInstance<SqlClass1>(ServiceProvider, "foo");

方案二:注册工厂委托

如果需要更灵活的控制,可以为每个类注册工厂:

// 在ConfigureServices中注册SqlClass1的工厂
services.AddTransient<Func<string, SqlClass1>>(sp => userName => 
    new SqlClass1(userName, sp.GetRequiredService<SqlConnection>()));

// 使用时直接获取工厂并调用
var sqlClass1Factory = ServiceProvider.GetRequiredService<Func<string, SqlClass1>>();
var x = sqlClass1Factory("foo");

修正后的完整代码示例

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

static class Program
{
    public static IServiceProvider ServiceProvider { get; private set; }

    static IHostBuilder CreateHostBuilder()
    {
        return Host.CreateDefaultBuilder().ConfigureServices((context, services) =>
        {
            // 注册默认SqlConnection(假设MySensibleDefaultSqlConnection是SqlConnection子类)
            services.AddTransient<SqlConnection, MySensibleDefaultSqlConnection>();
            
            // 注册需要注入的类
            services.AddTransient<SqlClass1>();
            services.AddTransient<SqlClass2>();
            // [...]
            services.AddTransient<SqlClass30>();
        });
    }

    static void Main()
    {
        var host = CreateHostBuilder().Build();
        ServiceProvider = host.Services;

        // 使用ActivatorUtilities创建带动态参数的实例
        var x = ActivatorUtilities.CreateInstance<SqlClass1>(ServiceProvider, "foo");
        // 对比原来的手动写法:var x = new SqlClass1("foo", new MySensibleDefaultSqlConnection());
    }
}

// 示例类定义
public class MySensibleDefaultSqlConnection : SqlConnection
{
    public MySensibleDefaultSqlConnection() : base("your-default-connection-string") { }
}

public class SqlClass1
{
    public SqlClass1(string userName, SqlConnection conn)
    {
        // 构造逻辑
    }
}

public class SqlClass2
{
    public SqlClass2(string userId, SqlConnection conn)
    {
        // 构造逻辑
    }
}

总结

你的核心想法完全正确——DI确实能帮你省去为每个类写默认构造函数的重复工作,统一管理依赖的创建逻辑,也方便单元测试时替换SqlConnection为模拟实现。只需要修正注册语法和动态参数的传递方式,代码就能正常运行。

内容的提问来源于stack exchange,提问作者J. Mini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:13:10