当前位置:首页 > C# > 正文

深入理解C#依赖注入的生命周期(瞬时/作用域/单例)——.NET Core开发必备指南

在现代C#开发中,尤其是使用.NET Core或.NET 5+构建应用程序时,依赖注入(Dependency Injection, 简称DI)已成为标准设计模式。它帮助我们实现松耦合、可测试和可维护的代码。而要真正掌握依赖注入,必须理解其三种核心生命周期: 瞬时(Transient)作用域(Scoped)单例(Singleton)

深入理解C#依赖注入的生命周期(瞬时/作用域/单例)——.NET Core开发必备指南 C#依赖注入 DI生命周期 瞬时作用域单例 .NET Core依赖注入 第1张

什么是依赖注入?

依赖注入是一种将对象所依赖的其他对象“注入”到该对象中的方式,而不是在类内部直接创建依赖。这样可以解耦组件,提高代码的灵活性和可测试性。

C#中的三种DI生命周期

在.NET Core中,服务容器(Service Container)通过 IServiceCollection 注册服务,并指定其生命周期。这三种生命周期决定了服务实例何时被创建、复用或销毁。

1. 瞬时(Transient)

每次从服务容器请求时,都会创建一个全新的实例。适用于轻量级、无状态的服务。

services.AddTransient<IMyService, MyService>();

2. 作用域(Scoped)

在同一个请求作用域内(例如一次HTTP请求),只创建一个实例;不同请求之间实例不同。常用于Web应用中的数据库上下文(如Entity Framework的DbContext)。

services.AddScoped<IMyService, MyService>();

3. 单例(Singleton)

整个应用程序生命周期内只创建一个实例,所有请求共享该实例。适用于有状态但线程安全的服务(需谨慎使用)。

services.AddSingleton<IMyService, MyService>();

实际代码示例

假设我们有一个简单的服务接口和实现:

public interface IOperation{    string OperationId { get; }}public class Operation : IOperation{    public string OperationId { get; } = Guid.NewGuid().ToString();}

Program.cs(.NET 6+)中注册三种生命周期:

var builder = WebApplication.CreateBuilder(args);// 注册三种生命周期的服务builder.Services.AddTransient<IOperation, Operation>();builder.Services.AddScoped<IOperationScoped, Operation>();builder.Services.AddSingleton<IOperationSingleton, Operation>();var app = builder.Build();

然后在一个控制器中注入它们:

[ApiController][Route("[controller]")]public class TestController : ControllerBase{    private readonly IOperation _transient;    private readonly IOperation _scoped;    private readonly IOperation _singleton;    public TestController(        IOperation transient,        IOperationScoped scoped,        IOperationSingleton singleton)    {        _transient = transient;        _scoped = scoped;        _singleton = singleton;    }    [HttpGet]    public IActionResult Get()    {        return Ok(new        {            Transient = _transient.OperationId,            Scoped = _scoped.OperationId,            Singleton = _singleton.OperationId        });    }}

多次访问该接口,你会发现:
- Transient 每次都不同
- Scoped 在同一次请求中相同(若在控制器内多次使用),但在不同HTTP请求中不同
- Singleton 始终相同

常见误区与最佳实践

  • 不要在Singleton服务中注入Scoped服务——会导致Scoped服务被提升为Singleton,可能引发线程安全问题。
  • Transient服务适合无状态、轻量级操作;避免在Transient中持有大量资源。
  • DbContext 应注册为Scoped,以确保每个请求使用独立的上下文。

总结

掌握 C#依赖注入 的三种生命周期(瞬时、作用域、单例)是构建高质量.NET应用的基础。正确选择生命周期不仅能提升性能,还能避免潜在的并发和内存问题。希望本教程能帮助你彻底理解 .NET Core依赖注入 的核心机制,写出更健壮的代码。

关键词回顾:C#依赖注入DI生命周期瞬时作用域单例.NET Core依赖注入