依赖注入(DI)-笔记

 

什么是依赖关系注入?

依赖关系注入是一种设计模式,用来解决类与类之间的紧耦合问题。

问题场景

文档首先展示了一个不好的例子

 
 
csharp
public class IndexModel : PageModel
{
    private readonly MyDependency _dependency = new MyDependency(); // 直接创建实例

    public void OnGet()
    {
        _dependency.WriteMessage("IndexModel.OnGet");
    }
}

这种写法有什么问题?

  1. 紧耦合:IndexModel直接依赖具体的MyDependency类
  2. 难以替换:如果要换成别的实现,必须修改IndexModel
  3. 难以测试:无法在单元测试中替换为模拟对象
  4. 配置分散:如果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");
    }
}

依赖注入的好处

  1. 松耦合:类只依赖接口,不依赖具体实现
  2. 易于替换:要换实现只需修改注册代码
  3. 易于测试:可以注入模拟对象进行单元测试
  4. 自动管理:框架负责创建和销毁对象

 

什么是链式依赖?

链式依赖就是指一个对象依赖另一个对象,而那个对象又依赖第三个对象,形成一条依赖链。

举个生活中的例子

想象你要做一顿饭:

  • 你需要一个厨师(主要服务)
  • 厨师需要刀具(厨师的依赖)
  • 刀具需要磨刀石来保持锋利(刀具的依赖)

这就形成了:你 → 厨师 → 刀具 → 磨刀石 的依赖链

代码示例

让我用更清晰的例子来说明:

 
 
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 时,容器会:

  1. 发现 UserController 需要 IUserService
  2. 发现 UserService 需要 IDatabase
  3. 先创建 Database
  4. 再创建 UserService(注入 Database
  5. 最后创建 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 时:

  1. 容器发现需要 IMyDependency
  2. 发现 MyDependency2 实现了 IMyDependency,但它需要 ILogger
  3. 容器先创建 ILogger
  4. 再创建 MyDependency2(注入 ILogger
  5. 最后创建 Index2Model(注入 MyDependency2

关键点

  • 你不需要手动管理这些依赖关系
  • 容器会自动解析整条链
  • 只要你正确注册了所有服务,容器就能处理任意复杂的依赖关系

 

参考文章: https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-10.0#overview-of-dependency-injection

 

posted @ 2026-01-05 15:02  鹰翱  阅读(4)  评论(0)    收藏  举报