C#的依赖注入是什么?如何在项目中配置?

来源:个人站长作者:上海网站建设头衔:草根站长
导读:本期聚焦于小伙伴创作的《C#的依赖注入是什么?如何在项目中配置?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#的依赖注入是什么?如何在项目中配置?》有用,将其分享出去将是对创作者最好的鼓励。

依赖注入(Dependency Injection,简称DI)是控制反转(IOC)思想的一种具体实现方式,核心是将对象的依赖关系由外部容器来管理和注入,而不是在对象内部主动创建依赖实例,从而减少代码之间的耦合程度。在C#的生态中,尤其是.Net Core及之后的框架,依赖注入已经成为内置的核心功能,几乎所有层级的服务都可以通过依赖注入来管理。

C#的依赖注入是什么?如何在项目中配置?

依赖注入的核心概念

依赖注入主要包含三个角色:服务(被依赖的对象)、服务容器(管理服务的注册和生命周期的容器)、消费者(需要使用服务的对象)。它的核心优势在于:

  • 降低耦合:消费者不需要关心依赖的创建细节,只需要定义依赖的接口或类型即可
  • 提升可测试性:可以很方便地替换依赖的实现,比如测试时使用模拟对象
  • 统一管理生命周期:服务容器可以统一控制依赖的创建、销毁时机

C#项目中配置依赖注入的步骤

1. 定义服务接口和实现

首先我们需要定义要注册的服务,通常先定义接口,再提供具体实现,这样更符合面向接口编程的原则。

// 定义服务接口
public interface IUserService
{
    string GetUserName(int userId);
}

// 定义服务实现
public class UserService : IUserService
{
    public string GetUserName(int userId)
    {
        // 模拟从数据库获取用户名称的逻辑
        return $"用户{userId}";
    }
}

2. 注册服务到容器

在.Net Core及之后的项目中,服务的注册通常在程序的启动阶段完成,也就是Program.cs文件中的WebApplicationBuilderServices属性上进行操作。服务的注册需要指定服务的生命周期,C#依赖注入内置了三种常见的生命周期:

生命周期类型说明
Transient每次请求服务时都会创建一个新的实例
Scoped在同一个请求范围内,多次获取服务会得到同一个实例,不同请求之间是不同实例
Singleton整个应用程序生命周期内,只会创建一个实例,所有请求共享该实例

以下是注册服务的代码示例:

var builder = WebApplication.CreateBuilder(args);

// 注册瞬态服务,每次获取都会创建新实例
builder.Services.AddTransient<IUserService, UserService>();

// 注册作用域服务,同请求内实例相同
// builder.Services.AddScoped<IUserService, UserService>();

// 注册单例服务,全局唯一实例
// builder.Services.AddSingleton<IUserService, UserService>();

var app = builder.Build();

3. 在消费者中注入服务

服务注册完成之后,就可以在需要使用服务的类中通过构造函数注入的方式获取服务实例,框架会自动从容器中找到对应的实现并注入。

// 控制器中注入服务示例
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    private readonly IUserService _userService;

    // 构造函数注入,框架自动传入IUserService的实现实例
    public UserController(IUserService userService)
    {
        _userService = userService;
    }

    [HttpGet("{id}")]
    public string Get(int id)
    {
        return _userService.GetUserName(id);
    }
}

如果是普通的非控制器类,只要该类本身也是通过依赖注入创建的,同样可以通过构造函数注入服务:

public class OrderService
{
    private readonly IUserService _userService;

    public OrderService(IUserService userService)
    {
        _userService = userService;
    }

    public string CreateOrder(int userId)
    {
        var userName = _userService.GetUserName(userId);
        return $"为用户{userName}创建订单";
    }
}

4. 手动获取服务(可选场景)

大部分场景下我们不需要手动获取服务,但是在一些特殊场景,比如需要在静态方法中获取服务,或者无法通过构造函数注入的场景,可以通过IServiceProvider来手动获取服务:

// 手动获取服务示例
public class ServiceHelper
{
    private readonly IServiceProvider _serviceProvider;

    public ServiceHelper(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public string GetUserNameManual(int userId)
    {
        // 从服务容器中获取IUserService实例
        using var scope = _serviceProvider.CreateScope();
        var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
        return userService.GetUserName(userId);
    }
}

注意事项

在配置依赖注入时需要注意几个问题:首先,注册的服务类型必须和注入时使用的类型匹配,否则会抛出找不到服务的异常;其次,要根据实际业务场景选择合适的生命周期,比如如果服务中持有数据库连接等需要释放的资源,不建议使用Singleton生命周期;最后,避免循环依赖,也就是A依赖B,B又依赖A的情况,这种情况会导致服务无法正确创建。

依赖注入C#IOC服务生命周期修改时间:2026-06-26 05:24:21

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。