.NET Core DI手动创建实例释放方法与工厂注册生命周期差异
问题1:实现框架自动释放手动创建的IDBCache实例的可行方案
.NET Core依赖注入容器只会自动释放自身托管创建的服务实例,手动new的实例要实现自动释放,可选择适配不同场景的方案:
- 方案1:.NET 8+ 使用键控服务(最简洁)
直接将IDBCache注册为以userId为Key的托管服务,容器自动处理生命周期:
容器会按照注册的生命周期(示例为瞬态,可根据需求改成Scoped/Singleton)自动释放实现了// 注册键控服务,根据userId区分实例 container.AddKeyedTransient<IDBCache>((sp, key) => new IDBCache((string)key, sp.GetRequiredService<IBLogic>())); // 注册工厂方便调用 container.AddSingleton<Func<string, IDBCache>>(sp => userId => sp.GetRequiredKeyedService<IDBCache>(userId));IDisposable/IAsyncDisposable的IDBCache实例。 - 方案2:低版本.NET 挂载到当前作用域释放
如果是ASP.NET Core场景,可将创建的实例注册到当前请求的释放队列:
非Web场景可在创建实例后,手动挂载到当前container.AddSingleton<Func<string, IHttpContextAccessor, IDBCache>>(p => (userId, accessor) => { var cache = new IDBCache(userId, p.GetRequiredService<IBLogic>()); // 挂载到当前请求,请求结束自动释放 accessor.HttpContext?.Response.RegisterForDispose(cache); return cache; });IServiceScope的释放列表,作用域销毁时自动释放。
问题2:用AddSingleton注册工厂委托的优势
你注册的Func<string, IDBCache>本身是一个无状态的委托对象,逻辑固定,不依赖任何作用域内的服务:
AddSingleton注册时,整个应用生命周期只会创建1次该委托实例,所有位置解析到的都是同一个委托,没有重复初始化的开销,性能最优,也不存在线程安全问题。- 如果用
AddTransient注册,每次解析工厂都会生成新的委托实例,完全无意义,只会产生不必要的内存分配和GC开销。 - 如果用
AddScoped注册,每个作用域都会生成一个新的委托实例,同样属于冗余操作,没有收益。
注意:如果后续工厂内部需要解析作用域服务,不能再用
AddSingleton注册工厂,否则会捕获根容器导致作用域服务泄漏,此时需改为AddScoped注册工厂,捕获当前作用域的服务提供者。
内容的提问来源于stack exchange,提问作者191180rk
相关产品推荐
相关产品推荐

