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

.NET非构造注入场景下,如何获取Program.cs已注册类实例

解决方案

1. 保留服务提供者引用

在Program.cs中,将构建完成的IServiceProvider保存到一个可全局访问的静态类中,用于后续实例获取:

var builder = WebApplication.CreateBuilder(args);

// 根据需求注册服务(仅选择一种生命周期)
builder.Services.AddSingleton<MyClass>();
// builder.Services.AddTransient<MyClass>();
// builder.Services.AddScoped<MyClass>();

// 注册接口与对应实现(支持动态获取场景)
builder.Services.AddTransient<IMyClass, MyClassA>();
builder.Services.AddTransient<IMyClass, MyClassB>();

var app = builder.Build();
// 将ServiceProvider注入静态定位器
ServiceLocator.Instance = app.Services;

// 后续中间件配置...
app.Run();

2. 实现ServiceLocator静态类

创建轻量静态类封装实例获取逻辑,供旧代码直接调用:

public static class ServiceLocator
{
    // 全局服务提供者实例
    public static IServiceProvider Instance { get; set; }

    /// <summary>
    /// 泛型方式获取实例
    /// </summary>
    public static T GetInstance<T>()
    {
        return Instance.GetRequiredService<T>();
    }

    /// <summary>
    /// 按Type类型获取实例(匹配需求中的GetInstance(Type)场景)
    /// </summary>
    public static object GetInstance(Type type)
    {
        return Instance.GetRequiredService(type);
    }
}

3. 在旧代码中获取实例

直接获取指定类型实例

// 对应你期望的调用方式
MyClass myInstance = (MyClass)ServiceLocator.GetInstance(typeof(MyClass));
// 泛型方式更简洁
MyClass myInstance = ServiceLocator.GetInstance<MyClass>();

动态获取接口的不同实现

public void MyFunc(string className)
{
    // 需传入完整命名空间+类名,跨程序集需追加程序集名称(如:myNamespace.MyClass, MyAssembly)
    var type = Type.GetType($"myNamespace.{className}");
    if (type == null)
    {
        throw new ArgumentException($"未找到目标类型:myNamespace.{className}");
    }

    IMyClass myClass = (IMyClass)ServiceLocator.GetInstance(type);
    myClass.DoSomething();
}

4. 处理Scoped生命周期服务

Scoped服务必须在作用域内使用,若旧代码不在请求作用域(如后台任务、离线脚本),需手动创建临时作用域:

// 创建临时作用域
using var scope = ServiceLocator.Instance.CreateScope();
var scopedProvider = scope.ServiceProvider;

// 在作用域内获取Scoped实例
var scopedInstance = scopedProvider.GetRequiredService<MyClass>();
// 使用实例...

注意事项

  • 过渡方案提示:ServiceLocator是重构过渡期的妥协方案,完成代码重构后务必替换为构造注入,避免服务定位器反模式带来的维护隐患
  • Type.GetType限制:目标类不在当前程序集时,需指定完整程序集名称,格式为命名空间.类名, 程序集名称
  • 异常处理:可根据业务需求将GetRequiredService替换为GetService,并处理实例为null的情况(GetRequiredService在找不到实例时会抛出异常)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 09:25:36