单例工厂存储的瞬态实例是否会表现为单例?该实现是否合理?
问题
我正在研读现有代码以理解依赖注入(DI)生命周期,现有代码中,注册为单例的PipelineFactory类会从字典中返回对应实例(若已存在),否则创建新的瞬态IPipeline实例并存入字典后返回。请问:
- 存储在该工厂内的这些瞬态实例是否会表现得像单例?
- 这种编码实现方式是否为良好的开发实践?
相关代码
Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Services .AddHostedService<Consumer>() .AddSingleton<IPipelineFactory, PipelineFactory>() .AddTransient<IPipeline, Pipeline>(); var app = builder.Build(); app.MapGet("/", (IPipelineFactory pipelineFactory) => { return $"Total pipelines: {pipelineFactory.GetPipelineCount()}"; }); app.Run();
PipelineFactory实现
public class PipelineFactory : IPipelineFactory { private readonly Dictionary<int, IPipeline> _pipelines = new(); private readonly IServiceProvider _serviceProvider; public PipelineFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IPipeline GetPipeline(int pipelineId) { if (!_pipelines.ContainsKey(pipelineId)) { using var scope = _serviceProvider.CreateScope(); _pipelines.Add(pipelineId, scope.ServiceProvider.GetRequiredService<IPipeline>()); } return _pipelines[pipelineId]; } public int GetPipelineCount() { return _pipelines.Count; } }
回答
1. 存储的瞬态实例是否表现得像单例?
是,这些IPipeline实例会完全表现出单例的行为:
- 由于
PipelineFactory是单例注册,它内部的_pipelines字典会在整个应用生命周期内持续存在。 - 针对同一个
pipelineId,第一次调用会创建IPipeline实例并存入字典,后续所有请求都会返回同一个实例,不会重新创建。 - 哪怕
IPipeline本身注册为瞬态,一旦被存入单例工厂的字典,就不会被GC回收(除非手动从字典移除),生命周期和单例完全一致。
2. 这种实现是否为良好的开发实践?
这种实现存在明显缺陷,不属于良好的开发实践,核心问题包括:
- 内存泄漏风险:字典会永久持有所有创建过的
IPipeline实例,直到应用关闭。如果pipelineId数量较多,会持续占用内存,无法被回收。 - DI生命周期混乱:手动从容器获取实例并持有,绕过了DI容器的生命周期管理机制。如果
IPipeline依赖了scoped类型的服务,会导致这些依赖服务无法被正确释放,引发资源泄漏或状态错误。 - 线程安全隐患:
Dictionary<TKey,TValue>不是线程安全集合,当多个并发请求同时调用GetPipeline创建新实例时,可能出现键重复添加、字典结构损坏等问题。 - 可测试性差:工厂直接依赖
IServiceProvider属于服务定位器模式,会增加单元测试的复杂度,无法方便地替换或模拟依赖。
优化建议
- 如果确实需要按
pipelineId复用实例,可以考虑使用按键注册的单例,或者实现带过期机制的缓存逻辑。 - 若不需要长期复用,应每次获取时创建新的瞬态实例,避免在单例容器中持有实例引用。
- 必须保证线程安全的话,改用
ConcurrentDictionary<int, IPipeline>替代普通Dictionary。 - 避免直接依赖
IServiceProvider,通过构造函数注入Func<IPipeline>来创建瞬态实例,保持DI的清晰性。
内容的提问来源于stack exchange,提问作者user1890098
相关产品推荐
相关产品推荐

