AddTransient, AddScoped, AddSingleton:C# 中的区别及示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

AddTransient、AddScoped 和 AddSingleton:如何不混淆 C# 服务生命周期

\n\n

您是否曾有过这样的想法:“为什么我的服务在请求之间保存了数据,尽管我并没有要求它这样做?”或者相反——“为什么每次都创建一个新对象,导致我丢失了状态?”

\n\n

欢迎来到 ASP.NET Core 中依赖注入 (Dependency Injection, DI) 的世界!这是初学者最强大但也最容易混淆的主题之一。今天,我们将剖析支撑 C# 对象管理的三大支柱:AddTransient、AddScoped 和 AddSingleton。

\n\n

到本文结束时,您不仅会理解它们的区别,还能在面试中自信地回答这个问题(是的,面试官超爱问这个!)。我们开始吧!

\n\n

什么是服务生命周期,为什么需要它?

\n\n

想象一下,您的应用程序是一家餐厅。服务就是厨师、服务员和餐具。生命周期决定了它们“存活”多久:

\n\n
    \n
  • Transient(瞬态) — 一次性员工。来了,做了一碗汤就走了。新订单来,换新员工。
  • \n
  • Scoped(作用域) — 一个班次的员工。在餐厅营业期间(即 HTTP 请求持续期间)为所有顾客服务。
  • \n
  • Singleton(单例) — 主厨,在餐厅的整个生命周期内工作。整个应用程序只有一个。
  • \n
\n\n

在 C# 中,此逻辑通过内置的 DI 容器实现。让我们看看代码。

\n\n

1. AddTransient — 每次都创建新实例

\n\n

何时使用: 无状态 (stateless) 的轻量级服务,不在调用之间存储数据。非常适合仓库、辅助类、工具类。

\n\n

工作原理: 每次您请求服务时(通过构造函数或直接从容器中),都会创建一个新对象。

\n\n
// 在 Program.cs 中注册\nbuilder.Services.AddTransient<IMyService, MyService>();\n\n// 服务示例\npublic interface IMyService\n{\n    Guid GetInstanceId();\n}\n\npublic class MyService : IMyService\n{\n    private readonly Guid _id = Guid.NewGuid();\n    public Guid GetInstanceId() => _id;\n}\n\n// 使用该服务的控制器\npublic class HomeController : Controller\n{\n    private readonly IMyService _service1;\n    private readonly IMyService _service2;\n\n    public HomeController(IMyService service1, IMyService service2)\n    {\n        _service1 = service1;\n        _service2 = service2;\n    }\n\n    public IActionResult Index()\n    {\n        ViewBag.Id1 = _service1.GetInstanceId();\n        ViewBag.Id2 = _service2.GetInstanceId();\n        // Id1 和 Id2 是不同的 GUID!\n        return View();\n    }\n}\n
\n\n

重要提示: 即使在同一个 HTTP 请求中,如果您在两个不同的地方注入 IMyService,您将得到两个不同的对象。这会消耗内存,但不会有数据“污染”的风险。

\n\n

2. AddScoped — 每个请求一个实例

\n\n

何时使用: 需要在单个 HTTP 请求内保持一致的服务。例如,Entity Framework Core 中的 DbContext、购物车服务、请求日志记录器。

\n\n

工作原理: 在单个 HTTP 请求(或作用域)内,创建一个实例。如果您多次请求它,您将得到同一个对象。但来自其他用户的每个新请求都会获得自己的实例。

\n\n
// 注册\nbuilder.Services.AddScoped<IScopedService, ScopedService>();\n\npublic interface IScopedService\n{\n    Guid GetInstanceId();\n}\n\npublic class ScopedService : IScopedService\n{\n    private readonly Guid _id = Guid.NewGuid();\n    public Guid GetInstanceId() => _id;\n}\n\n// 在同一个控制器中\npublic                

博客

书籍推荐