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

.NET IServiceProvider如何获取已创建瞬态服务实例且不生成新实例

核心结论

.NET 内置依赖注入容器原生不支持查询已创建的瞬态生命周期服务实例,这是容器的设计决定,不是使用方式错误:

  • 瞬态(Transient)生命周期的规则就是每次向容器发起服务解析请求时,都会创建全新的服务实例
  • 对比单例(Singleton)、作用域(Scoped)生命周期,容器会持有后两类服务的实例引用直到对应生命周期结束,但瞬态服务容器不会保存任何引用,实例生命周期完全由消费方控制,容器本身没有已创建瞬态实例的列表存储
  • 你尝试的构造函数注入IEnumerable<ISomeService>、GetServices<ISomeService>()、GetRequiredServices<ISomeService>()本质都是向容器发起服务解析请求,必然触发新实例创建,符合预期行为。
实现方案

要实现“不创建新实例、获取所有已存在瞬态实例”的需求,需要自行实现实例跟踪逻辑,推荐侵入性最低的实现方式如下:

步骤1:实现无内存泄漏的瞬态实例跟踪器

使用ConditionalWeakTable存储实例引用,不会阻止实例被垃圾回收,避免内存泄漏:

using System.Runtime.CompilerServices;

public class TransientInstanceTracker
{
    // 键为被跟踪的瞬态实例,值无实际意义,仅利用该类型的弱引用特性
    private readonly ConditionalWeakTable<object, object> _trackedInstances = new();

    /// <summary>
    /// 记录新创建的瞬态实例
    /// </summary>
    public void Track(object serviceInstance)
    {
        if (serviceInstance == null) return;
        _trackedInstances.TryAdd(serviceInstance, null!);
    }

    /// <summary>
    /// 获取指定类型所有已创建、且未被GC回收的瞬态实例
    /// </summary>
    public IEnumerable<TService> GetExistingInstances<TService>()
    {
        foreach (var entry in _trackedInstances)
        {
            if (entry.Key is TService service)
            {
                yield return service;
            }
        }
    }
}

步骤2:注册服务时接入跟踪逻辑

将跟踪器注册为单例,修改瞬态服务的注册方式,在实例创建时自动加入跟踪:

public void ConfigureServices(IServiceCollection services)
{
    // 注册单例跟踪器
    services.AddSingleton<TransientInstanceTracker>();
    // 替换原有的AddTransient注册,通过工厂创建实例时自动跟踪
    services.AddTransient<ISomeService, SomeService>(sp =>
    {
        var service = new SomeService();
        sp.GetRequiredService<TransientInstanceTracker>().Track(service);
        return service;
    });
}

步骤3:查询已存在实例

需要获取实例列表时,直接注入跟踪器调用查询方法即可,整个过程不会触发新实例创建:

public class AnotherService 
{
    public AnotherService(TransientInstanceTracker tracker) 
    {
        // 获取所有已存在的ISomeService瞬态实例,无新实例生成
        IEnumerable<ISomeService> existingInstances = tracker.GetExistingInstances<ISomeService>();
    }
}

注意:不要使用List<object>、HashSet<object>等强引用集合存储瞬态实例,这类集合会持有实例的强引用,导致实例永远无法被垃圾回收,最终引发内存泄漏。

其他可选方案

如果不想自行实现跟踪逻辑,也可以替换内置DI容器为第三方DI框架(如Autofac、Unity等),但绝大多数第三方DI容器默认也不会跟踪瞬态实例,需要手动开启实例跟踪配置,且同样需要注意弱引用、内存泄漏相关问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:54:23