将瞬态实例作为字典存储在单例实例中

问题描述 投票:0回答:1

我正在跟踪一个现有的代码库,试图理解 DI 生命周期,在下面的代码中,我们有一个注册为单例的 Factory 类,它从字典中返回一个实例(如果存在),或者创建一个新的瞬态实例并返回它同时将其存储在字典中。

我的问题是在工厂内创建和存储的瞬态实例是否会开始像单例一样运行?这是一个好的编码方法吗?

我的程序.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();

我的工厂实施,

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;
        }
    }
c# .net dependency-injection
1个回答
0
投票

我的问题是在工厂内创建和存储的瞬态实例是否会开始像单例一样运行?

是的,有效。

这是一个好的编码方法吗?

可以说——不。这在某种程度上是可以容忍的,但我强烈建议重新考虑这种方法。基本上,您依赖于管道在内部不使用任何范围服务的事实。如果您没有作用域依赖项,则无需创建作用域 (

 _serviceProvider.CreateScope()
)。

如果您执行以下操作:

if (!_pipelines.ContainsKey(pipelineId))
{
    using var scope = _serviceProvider.CreateScope();
    _pipelines.Add(pipelineId, scope.ServiceProvider.GetRequiredService<IPipeline>());                                
}

有几个问题:

  1. 范围在添加到字典后立即被处置,因此由它创建/管理的所有一次性依赖项也将被处置
  2. 您正在创建所谓的强制依赖,这可能会导致不需要的/不希望的行为。例如,如果管道使用 EF(通常是有范围的),那么由于更改跟踪(用于创建/更新操作),它可能会导致性能大幅下降和内存泄漏(如果您“处理”处置问题)。

另请参阅:

© www.soinside.com 2019 - 2024. All rights reserved.