<C#> 详细介绍.NET 依赖注入
在 .NET 开发中,依赖注入(Dependency Injection,简称 DI)是一种设计模式,它可以增强代码的可测试性、可维护性和可扩展性。以下是对 .NET 依赖注入的详细介绍:
1. 什么是依赖注入
在软件开发里,当一个类需要使用另一个类的功能时,就会产生依赖关系。传统做法是在类的内部创建依赖对象,这样会使代码耦合度变高,不利于测试和维护。而依赖注入则是将依赖对象的创建和管理工作交给外部容器,让类只专注于自身的业务逻辑。
例如,有一个 OrderService 类需要使用 EmailService 类来发送邮件,传统方式是在 OrderService 内部创建 EmailService 实例:
public class EmailService
{public void SendEmail(string message){// 发送邮件的逻辑Console.WriteLine($"Sending email: {message}");}
}public class OrderService
{private readonly EmailService _emailService;public OrderService(){_emailService = new EmailService();}public void ProcessOrder(){// 处理订单的逻辑_emailService.SendEmail("Order processed successfully.");}
}
使用依赖注入,OrderService 不再自己创建 EmailService 实例,而是通过构造函数接收:
public class OrderService
{private readonly IEmailService _emailService;public OrderService(IEmailService emailService){_emailService = emailService;}public void ProcessOrder(){// 处理订单的逻辑_emailService.SendEmail("Order processed successfully.");}
}
2. .NET 中的依赖注入容器
.NET 提供了内置的依赖注入容器,它能够管理对象的生命周期和依赖关系。在 Startup.cs(.NET 5 及之前版本)或者 Program.cs(.NET 6 及之后版本)中配置依赖注入。
2.1 注册服务
在 .NET 中,服务可以通过不同的生命周期进行注册,主要有以下三种:
- 单例(Singleton):在整个应用程序生命周期中,只创建一个服务实例。
- 作用域(Scoped):在每个请求的生命周期内,只创建一个服务实例。
- 瞬态(Transient):每次请求服务时,都会创建一个新的服务实例。
以下是在 .NET 6 的 Program.cs 中注册服务的示例:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;var host = Host.CreateDefaultBuilder(args).ConfigureServices((hostContext, services) =>{// 注册单例服务services.AddSingleton<IEmailService, EmailService>();// 注册作用域服务services.AddScoped<IOrderService, OrderService>();// 注册瞬态服务services.AddTransient<ITransientService, TransientService>();}).Build();// 使用服务
var orderService = host.Services.GetRequiredService<IOrderService>();
orderService.ProcessOrder();host.Run();
2.2 解析服务
通过 IServiceProvider 接口可以从依赖注入容器中解析服务。在上面的示例中,使用 host.Services.GetRequiredService<IOrderService>() 方法获取 IOrderService 的实例。
3. 使用依赖注入
一旦服务被注册到 IServiceCollection,你可以通过构造函数注入、属性注入或方法注入来使用这些服务。
构造函数注入
public class HomeController : Controller
{private readonly IUserService _userService;public HomeController(IUserService userService){_userService = userService;}public IActionResult Index(){var users = _userService.GetAllUsers();return View(users);}
}
属性注入
public class HomeController : Controller
{public IUserService UserService { get; set; }public IActionResult Index(){var users = UserService.GetAllUsers();return View(users);}
}
方法注入 (不常用)
public class HomeController : Controller
{public IActionResult Index([FromServices] IUserService userService){var users = userService.GetAllUsers();return View(users);}
}
在某些情况下,你可能需要在非控制器或非组件类中访问服务。你可以通过 IServiceProvider 来实现这一点:
// 在 Startup 或 Program.cs 中构建的应用程序实例中获取服务提供者
var serviceProvider = app.Services; var userService = serviceProvider.GetRequiredService<IUserService>();
4. 依赖注入的优点
- 可测试性:因为依赖对象是通过构造函数注入的,所以在单元测试时可以轻松地使用模拟对象来替代真实的依赖对象。
- 可维护性:当依赖对象发生变化时,只需要在依赖注入容器中修改注册配置,而不需要修改使用依赖的类。
- 可扩展性:可以方便地替换或添加新的依赖对象,而不会影响现有的代码。
5. 依赖注入的使用场景
- Web 应用开发:在 ASP.NET Core 应用中,控制器、中间件等组件可以通过依赖注入获取所需的服务。
- 测试驱动开发(TDD):依赖注入使得编写单元测试更加容易,因为可以使用模拟对象来隔离被测试的类。
- 大型项目开发:在大型项目中,使用依赖注入可以有效地管理组件之间的依赖关系,降低代码的耦合度。
总结
依赖注入是 .NET 开发中非常重要的设计模式,它通过将依赖对象的创建和管理工作交给外部容器,提高了代码的可测试性、可维护性和可扩展性。.NET 提供了内置的依赖注入容器,开发者可以根据需要注册不同生命周期的服务,并从容器中解析服务实例。
相关文章:
<C#> 详细介绍.NET 依赖注入
在 .NET 开发中,依赖注入(Dependency Injection,简称 DI)是一种设计模式,它可以增强代码的可测试性、可维护性和可扩展性。以下是对 .NET 依赖注入的详细介绍: 1. 什么是依赖注入 在软件开发里࿰…...
布局决定终局:基于开源AI大模型、AI智能名片与S2B2C商城小程序的战略反推思维
摘要:在商业竞争日益激烈的当下,布局与终局预判成为企业成功的关键要素。本文探讨了布局与终局预判的智慧性,强调其虽无法做到百分之百准确,但能显著提升思考能力。终局思维作为重要战略工具,并非一步到位的战略部署&a…...
构建面向大模型训练与部署的一体化架构:从文档解析到智能调度
作者:汪玉珠|算法架构师 标签:大模型训练、数据集构建、GRPO、自监督聚类、指令调度系统、Qwen、LLaMA3 🧭 背景与挑战 随着 Qwen、LLaMA3 等开源大模型不断进化,行业逐渐从“能跑通”迈向“如何高效训练与部署”的阶…...
告别循环!用Stream优雅处理集合
什么是stream? 也叫Stream流,是jdk8新增的一套API(java.util.stream.*)可以用于操作集合或者数组的数据。 优势:Stream流大量的结合了Lambda语法的风格编程,提供了一种更加强大,更加简单的方式…...
Linux电源管理、功耗管理 和 发热管理 (CPUFreq、CPUIdle、RPM、thermal、睡眠 和 唤醒)
1 架构图 1.1 Linux内核电源管理的整体架构 《Linux设备驱动开发详解:基于最新的Linux4.0内核》图19.1 1.2 通用的低功耗软件栈 《SoC底层软件低功耗系统设计与实现》 1.3 低功耗系统的架构设计;图1-3 2 系统级睡眠和唤醒管理 Linux系统的待机、睡眠…...
OSCP - Proving Grounds -FunboxEasy
主要知识点 弱密码路径枚举文件上传 具体步骤 首先是nmap扫描一下,虽然只有22,80和3306端口,但是事情没那么简单 Nmap scan report for 192.168.125.111 Host is up (0.45s latency). Not shown: 65532 closed tcp ports (reset) PORT …...
探索 Go 与 Python:性能、适用场景与开发效率对比
1 性能对比:执行速度与资源占用 1.1 Go 的性能优势 Go 语言被设计为具有高效的执行速度和低资源占用。它编译后生成的是机器码,能够直接在硬件上运行,避免了 Python 解释执行的开销。 以下是一个用 Go 实现的简单循环计算代码: …...
c++:构造函数(Constructor)与析构函数(Destructor)
目录 为什么我们需要构造函数? 什么是构造函数? 🧬 本质:构造函数是“创建对象的一部分” 为什么 需要析构函数? 什么是析构函数? 析构函数的核心作用 ❗注意点 为什么我们需要构造函数?…...
三周年创作纪念日
文章目录 回顾与收获三年收获的五个维度未来的展望致谢与呼唤 亲爱的社区朋友们,大家好! 今天是 2025 年 4 月 14 日,距离我在 2022 年 4 月 14 日发布第一篇技术博客《SonarQube 部署》整整 1,095 天。在这条创作之路上,我既感慨…...
Vue 3 国际化实战:支持 Element Plus 组件和语言持久化
目录 Vue 3 国际化实战:支持 Element Plus 组件和语言持久化实现效果:效果一、中英文切换效果二、本地持久化存储效果三、element Plus国际化 vue3项目国际化实现步骤第一步、安装i18n第二步、配置i18n的en和zh第三步:使用 vue-i18n 库来实现…...
1.阿里云快速部署Dify智能应用
一、宝塔面板 宝塔面板是一款功能强大且易于使用的服务器管理软件,支持Linux和Windows系统,通过web端可视化操作,优化了建站流程,提供安全管理、计划任务、文件管理以及软件管理等功能。 1.1 宝塔面板的特点与优势 易用性 宝塔面…...
Ubuntu与windows时间同步
由于ubuntu每次重启后时间老是不对,所以使用ntp服务,让ubuntu作为客户端,去同步windows时间。 一、windows服务端配置 1、启用ntp服务 # 启动W32Time服务(若未启动) net start w32time # 配置服务为NTP模式 w32tm /…...
在pycharm配置虚拟环境和jupyter,解决jupyter运行失败问题
记录自己pycharm环境配置和解决问题的流程。 解决pycharm无法运行jupyter代码,仅运行import板块显示运行失败,但是控制台不输出任何错误信息,令人困惑。 遇到的问题是:运行代码左下角显示运行失败但是有没有任何的输出错误信息。 …...
Vue 技术解析:从核心概念到实战应用
Vue.js 是一款流行的渐进式前端框架,以其简洁的 API、灵活的组件化结构和高效的响应式数据绑定而受到开发者的广泛欢迎。本文将深入解析 Vue 技术的核心概念、原理和应用场景,帮助开发者更好地理解和使用 Vue.js。 一、Vue 的设计哲学与核心概念 &…...
Series和 DataFrame是 Pandas 库中的两种核心数据结构
Series 和 DataFrame 是 Pandas 库中的两种核心数据结构,它们各有特点和用途。理解它们之间的区别有助于更高效地进行数据分析和处理。以下是 Series 和 DataFrame 的主要区别: 1. 维度 Series:是一维的数组,可以存储任何类型的…...
关于异步消息队列的详细解析,涵盖JMS模式对比、常用组件分析、Spring Boot集成示例及总结
以下是关于异步消息队列的详细解析,涵盖JMS模式对比、常用组件分析、Spring Boot集成示例及总结: 一、异步消息核心概念与JMS模式对比 1. 异步消息核心组件 组件作用生产者发送消息到消息代理(如RabbitMQ、Kafka)。消息代理中间…...
利用 Python 进行股票数据可视化分析
在金融市场中,股票数据的可视化分析对于投资者和分析师来说至关重要。通过可视化,我们可以更直观地观察股票价格的走势、交易量的变化以及不同股票之间的相关性等。 Python 作为一种功能强大的编程语言,拥有丰富的数据处理和可视化库…...
【Docker】离线安装Docker
背景 离线安装Docker的必要性,第一,在目前数据安全升级的情况下,很多外网已经基本不好访问了。第二,如果公司有对外部署的需求,那么难免会存在对方只有内网的情况,那么我们就要做到学会离线安装。 下载安…...
kubectl命令补全以及oc命令补全
kubectl命令补全 1.安装bash-completion 如果你用的是Bash(默认情况下是),先安装补全功能支持包 sudo apt update sudo apt install bash-completion -y2.为kubectl 启用补全功能 会话中临时: source <(kubectl completion bash)持久化配置&#x…...
《 C++ 点滴漫谈: 三十三 》当函数成为参数:解密 C++ 回调函数的全部姿势
一、前言 在现代软件开发中,“解耦” 与 “可扩展性” 已成为衡量一个系统架构优劣的重要标准。而在众多实现解耦机制的技术手段中,“回调函数” 无疑是一种高效且广泛使用的模式。你是否曾经在编写排序算法时,希望允许用户自定义排序规则&a…...
极简cnn-based手写数字识别程序
1.先看看识别效果: 这个程序识别的是0~9的一组手写数字,这是最终的识别效果,为1,代表识别成功,0为失败。 然后数据源是:ds deeplake.load(hub://activeloop/optical-handwritten-digits-train)里面是一组…...
C++核心机制-this 指针传递与内存布局分析
示例代码 #include<iostream> using namespace std;class A { public:int a;A() {printf("A:A()的this指针:%p!\n", this);}void funcA() {printf("A:funcA()的this指针:%p!\n", this);} };class B { public:int b;B() {prin…...
vue3 history路由模式刷新页面报错问题解决
在使用history路由模式时刷新网页提示404错误,这是改怎么办呢。 官方解决办法 https://router.vuejs.org/zh/guide/essentials/history-mode.html...
PHP爬虫教程:使用cURL和Simple HTML DOM Parser
一个关于如何使用PHP的cURL和HTML解析器来创建爬虫的教程,特别是处理代理信息的部分。首先,我需要确定用户的需求是什么。可能他们想从某个网站抓取数据,但遇到了反爬措施,需要使用代理来避免被封IP。不过用户没有提到具体的目标网…...
Web前端开发——格式化文本与段落(上)
一、学习目标 网页内容的排版包括文本格式化、段落格式化和整个页面的格式化,这是设计个网页的基础。文本格式化标记分为字体标记、文字修饰标记。字体标记和文字修饰标记包括对于字体样式的一些特殊修改。段落格式化标记分为段落标记、换行记、水平分隔线标记等。…...
技术方案选型要考虑哪些点?
在概要设计阶段,技术方案选型是核心环节之一,需综合考虑系统需求、技术可行性、团队能力及长期维护成本。以下是技术方案选型需包含的核心内容及设计要点,结合行业实践和搜索结果中的方法论: 理论 一、系统架构选型 整体架构模式…...
前端工程化之自动化构建
自动化构建 自动化构建的基本知识历史云构建 和 自动化构建 的区别:部署环境:构建:构建产物构建和打包的性能优化页面加载优化构建速度优化 DevOps原则反馈的技术实践 encode-bundlepackage.json解读src/cli-default.tssrc/cli-node.tssrc/cl…...
3.2.2.1 Spring Boot配置静态资源映射
在Spring Boot中配置静态资源映射,可以通过默认路径或自定义配置实现。默认情况下,Spring Boot会在classpath:/static/等目录下查找静态资源。若需自定义映射,可通过实现WebMvcConfigurer接口的addResourceHandlers方法或在全局配置文件中设置…...
# 更换手机热点后secureCRT无法连接centOS7系统
更换手机热点后secureCRT无法连接centOS7系统 一、问题描述 某些情况下,我们可能使用手机共享热点而给电脑联网。本来用一个手机热点共享网络时,SecureCRT可以正常连接到CentOS 7虚拟机,当更换一个手机热点时,突然发现SecureCR…...
【高性能缓存Redis_中间件】三、redis 精通:性能优化与生产实践
一、引言 在前两篇 Redis 消息队列的文章中,我们掌握了基础使用和高级特性。本文作为系列终篇,将聚焦生产环境的性能优化与全流程实践,请各位跟随小编的步伐一起构建高可靠、高性能的消息处理系统(文章中的演示均为Centos7的背…...
