依赖注入(Dependency Injection,简称DI)是控制反转(IOC)思想的一种具体实现方式,在.NET开发中,通过依赖注入可以将对象的创建和依赖关系的管理交给容器处理,避免手动创建依赖对象带来的高耦合问题。.NET从.NET Core开始就内置了轻量级的依赖注入容器,不需要引入第三方框架就能实现依赖注入功能。

依赖注入的核心概念
依赖注入的核心是将依赖对象的创建权从业务代码中转移出去,由容器统一管理。它主要包含三个角色:
- 服务(Service):需要被注册到容器中的类或接口实现,也就是被依赖的对象。
- 容器(Container):负责管理服务的注册、创建和生命周期的对象。
- 消费者(Consumer):需要使用服务的类,通过注入的方式获取服务实例。
.NET中服务的注册
在.NET项目中,服务的注册通常在程序的启动阶段完成,对于ASP.NET Core项目,注册逻辑一般写在Program.cs文件的WebApplicationBuilder的Services属性中。.NET内置容器支持三种不同的服务生命周期,开发者需要根据实际需求选择合适的生命周期。
服务生命周期类型
| 生命周期 | 说明 |
|---|---|
| Transient(瞬时) | 每次请求服务时,容器都会创建一个新的实例,适合轻量级的、无状态的服务。 |
| Scoped(作用域) | 在同一个请求作用域内,容器只会创建一个实例,适合需要保持请求内状态的服务。 |
| Singleton(单例) | 整个应用程序生命周期内,容器只会创建一个实例,适合全局共享的服务。 |
下面是服务注册的基础代码示例:
// 定义服务接口
public interface IUserService
{
string GetUserName(int userId);
}
// 定义服务实现类
public class UserService : IUserService
{
public string GetUserName(int userId)
{
return $"用户ID:{userId}";
}
}
// 在Program.cs中注册服务
var builder = WebApplication.CreateBuilder(args);
// 注册瞬时服务
builder.Services.AddTransient<IUserService, UserService>();
// 注册作用域服务
// builder.Services.AddScoped<IUserService, UserService>();
// 注册单例服务
// builder.Services.AddSingleton<IUserService, UserService>();
var app = builder.Build();
常见的注入方式
构造函数注入
构造函数注入是.NET中最推荐、最常用的注入方式,容器会在创建消费者实例时,自动匹配构造函数中需要的服务参数,完成依赖注入。这种方式能够明确类的依赖关系,也方便进行单元测试。
以下是控制器中使用构造函数注入的示例:
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
// 构造函数注入,容器会自动传入IUserService的实例
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
public string GetUser(int id)
{
return _userService.GetUserName(id);
}
}
属性注入
.NET内置的依赖注入容器默认不支持属性注入,如果需要使用属性注入,可以引入第三方IOC容器比如Autofac,或者手动从容器中获取服务。不过官方更推荐构造函数注入,属性注入容易导致依赖关系不明确,不建议优先使用。
手动获取服务实例
在某些特殊场景下,比如无法使用构造函数注入的地方,可以通过IServiceProvider手动获取服务实例。需要注意避免直接调用GetService导致的内存泄漏问题,尤其是Scoped生命周期的服务。
public class TestService
{
public void DoWork(IServiceProvider serviceProvider)
{
// 手动获取瞬时服务实例
var userService = serviceProvider.GetService<IUserService>();
if (userService != null)
{
var name = userService.GetUserName(1);
}
}
}
依赖注入的注意事项
在使用.NET依赖注入时,需要注意几个常见问题:首先,注册的服务生命周期要合理,比如Scoped服务不能注入到Singleton服务中,否则会导致Scoped服务变成单例,引发状态混乱。其次,不要过度使用依赖注入,对于简单的、无依赖的类,不需要强行注册到容器中。最后,服务的注册顺序不影响注入结果,容器会根据类型自动匹配对应的实现。
Dependency_Injection.NETIOC服务生命周期构造函数注入修改时间:2026-07-11 00:51:32