依赖注入(DI)-笔记
什么是依赖关系注入?
依赖关系注入是一种设计模式,用来解决类与类之间的紧耦合问题。
问题场景
文档首先展示了一个不好的例子:
csharp
public class IndexModel : PageModel
{
private readonly MyDependency _dependency = new MyDependency(); // 直接创建实例
public void OnGet()
{
_dependency.WriteMessage("IndexModel.OnGet");
}
}
这种写法有什么问题?
- 紧耦合:IndexModel直接依赖具体的MyDependency类
- 难以替换:如果要换成别的实现,必须修改IndexModel
- 难以测试:无法在单元测试中替换为模拟对象
- 配置分散:如果MyDependency还有其他依赖,配置会很乱
解决方案:依赖注入
第一步:定义接口
csharp
public interface IMyDependency
{
void WriteMessage(string message);
}
第二步:实现接口
csharp
public class MyDependency : IMyDependency
{
public void WriteMessage(string message)
{
Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
}
}
第三步:注册服务
csharp
// 在Program.cs中注册
builder.Services.AddScoped<IMyDependency, MyDependency>();
第四步:通过构造函数注入
csharp
public class Index2Model : PageModel
{
private readonly IMyDependency _myDependency;
// 通过构造函数接收依赖
public Index2Model(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public void OnGet()
{
_myDependency.WriteMessage("Index2Model.OnGet");
}
}
依赖注入的好处
- 松耦合:类只依赖接口,不依赖具体实现
- 易于替换:要换实现只需修改注册代码
- 易于测试:可以注入模拟对象进行单元测试
- 自动管理:框架负责创建和销毁对象
什么是链式依赖?
链式依赖就是指一个对象依赖另一个对象,而那个对象又依赖第三个对象,形成一条依赖链。
举个生活中的例子
想象你要做一顿饭:
- 你需要一个厨师(主要服务)
- 厨师需要刀具(厨师的依赖)
- 刀具需要磨刀石来保持锋利(刀具的依赖)
这就形成了:你 → 厨师 → 刀具 → 磨刀石 的依赖链
代码示例
让我用更清晰的例子来说明:
csharp
// 第三层依赖:数据库连接
public interface IDatabase
{
void Save(string data);
}
public class Database : IDatabase
{
public void Save(string data)
{
Console.WriteLine($"保存到数据库: {data}");
}
}
// 第二层依赖:用户服务(依赖数据库)
public interface IUserService
{
void CreateUser(string name);
}
public class UserService : IUserService
{
private readonly IDatabase _database;
public UserService(IDatabase database) // UserService依赖IDatabase
{
_database = database;
}
public void CreateUser(string name)
{
_database.Save($"用户: {name}");
}
}
// 第一层:控制器(依赖用户服务)
public class UserController
{
private readonly IUserService _userService;
public UserController(IUserService userService) // Controller依赖IUserService
{
_userService = userService;
}
public void Register(string name)
{
_userService.CreateUser(name);
}
}
```
## 依赖链的形成
在这个例子中,依赖链是这样的:
```
UserController → IUserService → IDatabase
当你请求 UserController 时,容器会:
- 发现
UserController需要IUserService - 发现
UserService需要IDatabase - 先创建
Database - 再创建
UserService(注入Database) - 最后创建
UserController(注入UserService)
注册服务
csharp
// 在 Program.cs 中注册所有服务
builder.Services.AddScoped<IDatabase, Database>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<UserController>();
容器自动解析
这就是依赖注入的魔力:你只需要告诉容器每个接口对应什么实现,容器会自动:
- 分析依赖关系
- 按正确顺序创建对象
- 自动注入依赖
更复杂的例子
文档中的 MyDependency2 例子:
csharp
public class MyDependency2 : IMyDependency
{
private readonly ILogger<MyDependency2> _logger; // MyDependency2依赖ILogger
public MyDependency2(ILogger<MyDependency2> logger)
{
_logger = logger;
}
}
public class Index2Model : PageModel
{
private readonly IMyDependency _myDependency; // Index2Model依赖IMyDependency
public Index2Model(IMyDependency myDependency)
{
_myDependency = myDependency;
}
}
依赖链:Index2Model → IMyDependency → ILogger
当创建 Index2Model 时:
- 容器发现需要
IMyDependency - 发现
MyDependency2实现了IMyDependency,但它需要ILogger - 容器先创建
ILogger - 再创建
MyDependency2(注入ILogger) - 最后创建
Index2Model(注入MyDependency2)
关键点
- 你不需要手动管理这些依赖关系
- 容器会自动解析整条链
- 只要你正确注册了所有服务,容器就能处理任意复杂的依赖关系
参考文章: https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-10.0#overview-of-dependency-injection

浙公网安备 33010602011771号