当前位置: 首页 > news >正文

深入理解WPF中的依赖注入和控制反转

在WPF开发中,依赖注入(Dependency Injection)和控制反转(Inversion of Control)是程序解耦的关键,在当今软件工程中占有举足轻重的地位,两者之间有着密不可分的联系。今天就以一个简单的小例子,简述如何在WPF中实现依赖注入和控制反转,仅供学习分享使用,如有不足之处,还请指正。

什么是依赖注入和控制反转?

依赖注入又称为依赖项注入,那什么是依赖项呢?比如在一个类A中,实现某中功能,而此功能是另外一个类B实现的,那就说明A依赖B,B就是A的依赖项。或者是另一个对象A所依赖的对象B。示例如下:

namespace DemoIoc
{public class MessageWriter{public void Print(string message){Console.WriteLine($"MessageWriter.Write(message: \"{message}\")");}}public class Worker : BackgroundService{private readonly MessageWriter writer = new();protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){writer.Print($"Worker running at: {DateTimeOffset.Now}");await Task.Delay(1_000, stoppingToken);}}}
}

 

注意:在上述示例中,Worker类依赖于MessageWriter类,所以MessageWriter就是Worker的依赖项。 硬编码的依赖项(如前面的示例)会产生问题,应避免使用

强依赖关系具有以下几个问题:

  • 如果要用不同的实现替换 MessageWriter,必须修改 Worker 类。
  • 如果 MessageWriter 具有依赖项,则必须由 Worker 类对其进行配置,且很难进行初始化。
  • 这种实现很难进行单元测试。

那如何解决上述依赖关系所造成的弊端呢?答案就是依赖项注入。可通过如下几个步骤实现:

  • 使用接口或基类将依赖关系实现抽象化。
  • 在服务容器中注册依赖关系。
  • 将服务注入到使用它的类的构造函数中。

 .NET 提供了一个内置的服务容器 IServiceProvider。 服务通常在应用启动时注册,并追加到 IServiceCollection。 添加所有服务后,可以使用 BuildServiceProvider 创建服务容器。 框架负责创建依赖关系的实例,并在不再需要时将其释放。

简单一句话说:依赖注入(DI)将所依赖的对象参数化,接口化,并且将依赖对象的创建和释放剥离出来,这样就做到了解耦,并且实现了控制反转(IoC)

控制反转(IoC)具有如下两个特点:

  • 高等级的代码不能依赖低等级的代码;
  • 抽象接口不能依赖具体实现;

控制反转解决代码的强耦合,增加了代码的可扩展性。依赖注入将依赖具体实现类和控制实现类的创建和释放,变成了依赖接口或抽象类,不再控制接口的创建和释放。两者之间相辅相成,互相成就。

WPF中实现依赖注入的步骤

1. 安装DI库

首先创建一个WPF应用程序,然后在Nuget包管理器中安装微软提供的依赖注入库【Microsoft.Extensions.DependencyInjection】,如下所示:

2. 创建接口和实现类

创建测试用的接口ITextService和实现类TextService,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace DemoIoc
{public interface ITextService{public string GetText();}public class TextService : ITextService{public string GetText(){return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");}}
}

 

3. 接口注入

在需要调用的地方(如:MainWindow)进行ITextService接口注入,如下所示:

namespace DemoIoc
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{private ITextService textService;public MainWindow(ITextService textService){this.textService = textService;InitializeComponent();}private void Window_Loaded(object sender, RoutedEventArgs e){this.txtCurrentTime.Text = textService.GetText();}}
}

 

注意:以上可以看出MainWindow依赖ITextService接口,而不依赖于接口的实现。这样就实现了依赖注入。

4. 配置容器

在启动程序App.xaml.cs中,添加当前对象成员,和服务提供对象,并在实例化服务对象的时候一次性注册,以便在后续需要的时候进行获取。如下所示:

namespace DemoIoc
{/// <summary>/// Interaction logic for App.xaml/// </summary>public partial class App : Application{/// <summary>/// 获取当前 App 实例/// </summary>public new static App Current => (App)Application.Current;/// <summary>/// 获取存放应用服务的容器/// </summary>public IServiceProvider ServiceProvider { get; }public App(){ServiceProvider = ConfigureServices();}/// <summary>/// 配置应用的服务/// </summary>private static IServiceProvider ConfigureServices(){var serviceCollection = new ServiceCollection().AddSingleton<ITextService,TextService>().AddSingleton<MainWindow>();return serviceCollection.BuildServiceProvider();}protected override void OnStartup(StartupEventArgs e){var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();mainWindow.Show();}}
}

 

注意:在此示例中,MainWindow通过服务注册的方式进行实例化,所以需要删除默认的App.xaml中StartUri属性设置,否则将提示默认构造函数不存在。

示例测试

经过上述步骤,就实现了WPF中依赖注入和控制反转,测试结果如下:

说明:正常输出,则表示依赖注入成功。

参考文档

1. .Net依赖项注入:https://learn.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection

以上就是依赖注入和控制反转的全部内容,希望可以抛砖引玉,一起学习,共同进步。

相关文章:

深入理解WPF中的依赖注入和控制反转

在WPF开发中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff09;和控制反转&#xff08;Inversion of Control&#xff09;是程序解耦的关键&#xff0c;在当今软件工程中占有举足轻重的地位&#xff0c;两者之间有着密不可分的联系。今天就以一个简单的小例子&…...

【CIO人物展】国家能源集团信息技术主管王爱军:中国企业数智化转型升级的内在驱动力...

王爱军 本文由国家能源集团信息技术主管王爱军投递并参与《2023中国数智化转型升级优秀CIO》榜单/奖项评选。丨推荐企业—锐捷网络 大数据产业创新服务媒体 ——聚焦数据 改变商业 随着全球信息化和网络化的进程日益加速&#xff0c;数字化转型已经成为当下各大企业追求的核心…...

(后续补充)vue+express、gitee pm2部署轻量服务器

首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 关闭防火墙 systemctl stop firewalld 重新载入防火墙使设置生效 firewall-cmd --reload 后端的 pm2.config.cjs …...

第G7周:Semi-Supervised GAN 理论与实战

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营-第G7周&#xff1a;Semi-Supervised GAN 理论与实战&#xff08;训练营内部成员可读&#xff09; &#x1f356; 原作者&#xff1a;K同学啊|接…...

美国Embarcadero产品经理Marco Cantù谈Delphi/C++ Builder目前开发应用领域

美国Embarcadero产品经理Marco Cant 日前在欧洲的一次信息技术会议上谈到了Delphi/C Builder目前开发应用领域&#xff1a;RAD Studio Delphi/C Builder目前应用于哪些开发领域&#xff1f;使用 Delphi 和 CBuilder 进行开发为当今众多企业提供了动力。 航空航天 大型数据采集 …...

【iOS】——知乎日报第三周总结

文章目录 一、获取新闻额外信息二、工具栏按钮的布局三、评论区文字高度四、评论区长评论和短评论的数目显示五、评论区的cell布局问题和评论消息的判断 一、获取新闻额外信息 新闻额外信息的URL需要通过当前新闻的id来获取&#xff0c;所以我将所有的新闻放到一个数组中&…...

leetcode每日一题-周复盘

前言 该系列文章用于我对一周中leetcode每日一题or其他不会的题的复盘总结。 一方面用于自己加深印象&#xff0c;另一方面也希望能对读者的算法能力有所帮助。 该复盘对我来说比较容易的题我会复盘的比较粗糙&#xff0c;反之较为细致 解答语言&#xff1a;Golang 周一&a…...

[NLP] LlaMa2模型运行在Mac机器

本文将介绍如何使用llama.cpp在MacBook Pro本地部署运行量化版本的Llama2模型推理&#xff0c;并基于LangChain在本地构建一个简单的文档Q&A应用。本文实验环境为Apple M1 芯片 8GB内存。 Llama2和llama.cpp Llama2是Meta AI开发的Llama大语言模型的迭代版本&#xff0c;…...

基于若依的ruoyi-nbcio流程管理系统增加仿钉钉流程设计(六)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 这节主要讲条件节点与并发节点的有效性检查&#xff0c;主要是增加这两个节点的子节点检查&#xff0c;因为…...

听GPT 讲Rust源代码--library/std(15)

题图来自 An In-Depth Comparison of Rust and C[1] File: rust/library/std/src/os/wasi/io/fd.rs 文件路径&#xff1a;rust/library/std/src/os/wasi/io/fd.rs 该文件的作用是实现与文件描述符&#xff08;File Descriptor&#xff09;相关的操作&#xff0c;具体包括打开文…...

腾讯云CVM服务器操作系统镜像大全

腾讯云CVM服务器的公共镜像是由腾讯云官方提供的镜像&#xff0c;公共镜像包含基础操作系统和腾讯云提供的初始化组件&#xff0c;公共镜像分为Windows和Linux两大类操作系统&#xff0c;如TencentOS Server、Windows Server、OpenCloudOS、CentOS Stream、CentOS、Ubuntu、Deb…...

Mxnet框架使用

目录 1.mxnet推理API 2.MXNET模型转ONNX 3.运行示例 1.mxnet推理API # 导入 MXNet 深度学习框架 import mxnet as mx if __name__ __main__:# 指定预训练模型的 JSON 文件json_file resnext50_32x4d # 指定模型的参数文件params_file resnext50_32x4d-0000.params # 使…...

每个程序员都应该自己写一个的:socket包装类

每个程序员都应该有自己的网络类。 下面是我自己用的socket类&#xff0c;支持所有我自己常用的功能&#xff0c;支持windows和unix/linux。 目录 客户端 服务端 非阻塞 获取socket信息 完整代码 客户端 作为socket客户端&#xff0c;只需要如下几个功能&#xff1a; //…...

JMeter:断言之响应断言

一、断言的定义 断言用于验证取样器请求或对应的响应数据是否返回了期望的结果。可以是看成验证测试是否预期的方法。 对于接口测试来说&#xff0c;就是测试Request/Response&#xff0c;断言即可以针对Request进行&#xff0c;也可以针对Response进行。但大部分是对Respons…...

RLHF的替代算法之DPO原理解析:从Zephyr的DPO到Claude的RAILF

前言 本文的成就是一个点顺着一个点而来的&#xff0c;成文过程颇有意思 首先&#xff0c;如上文所说&#xff0c;我司正在做三大LLM项目&#xff0c;其中一个是论文审稿GPT第二版&#xff0c;在模型选型的时候&#xff0c;关注到了Mistral 7B(其背后的公司Mistral AI号称欧洲…...

U盘显示无媒体怎么办?方法很简单

当出现U盘无媒体情况时&#xff0c;您可以在磁盘管理工具中看到一个空白的磁盘框&#xff0c;并且在文件资源管理器中不会显示出来。那么&#xff0c;导致这种问题的原因是什么呢&#xff1f;我们又该怎么解决呢&#xff1f; 导致U盘无媒体的原因是什么&#xff1f; 当您遇到上…...

进销存管理系统如何提高供应链效率?

供应链和进销存系统之间有着密切的联系。进销存系统是供应链管理的一部分&#xff0c;用于跟踪和管理产品的采购、库存和销售。进销存管理是供应链管理的核心流程之一&#xff0c;它有助于提高效率、降低成本、增加盈利&#xff0c;同时确保客户满意度&#xff0c;这对于企业的…...

用AI魔法打败AI魔法

全文均为AI创作。 此为内容创作模板&#xff0c;在发布之前请将不必要的内容删除当前&#xff0c;AI技术的广泛应用为社会公众提供了个性化智能化的信息服务&#xff0c;也给网络诈骗带来可乘之机&#xff0c;如不法分子通过面部替换语音合成等方式制作虚假图像、音频、视频仿…...

Java 中的final:不可变性的魔法之旅

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 Java 中的final&#xff1a;不可变性的魔法之旅 前言第一&#xff1a;了解final变量第二&#xff1a;final方法第三&#xff1a;final类第四&#xff1a;final参数第五&#…...

Alfred 5 for mac(最好用的苹果mac效率软件)中文最新版

Alfred 5 Mac是一款非常实用的工具&#xff0c;它可以帮助用户更加高效地使用Mac电脑。用户可以学会使用快捷键、全局搜索、快速启动应用程序、使用系统维护工具、快速复制粘贴文本以及自定义设置等功能&#xff0c;以提高工作效率。 Alfred for Mac 的一些主要功能包括&#…...

FPGA实现SRIO高速图像传输方案,设计模式(C++)详解——状态模式(State)(2)。

FPGA实现SRIO图像视频传输技术方案 基于Serial RapidIO Gen2协议的高性能图像视频传输方案&#xff0c;采用FPGA作为核心处理平台&#xff0c;提供完整的6套工程源码及技术支持。该方案适用于高速数据采集、实时图像处理等场景。 硬件架构设计 采用Xilinx Kintex-7系列FPGA作为…...

MQTT(消息队列遥测传输)

MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;是一种轻量级、基于发布/订阅模式的消息传输协议&#xff0c;专为受限设备、低带宽、高延迟、不稳定网络的物联网通信设计的。MQTT诞生于1999年&#xff0c;目的是用最小的网…...

InfluxDB(一)——一个高效处理数据的时序数据库

目录 一、什么是时序数据库InfluxDB&#xff1f; 关系型数据库&#xff08;行式存储&#xff09;是怎么存的&#xff1f; 时序数据库&#xff08;列式存储&#xff09;是怎么存的&#xff1f; 二、InfluxDB的特点 1. 极致的写入性能 2. 高效的存储压缩 3. 独特的数据模型…...

React 19 新特性吐槽:别再整那些花里胡哨的玩意儿了!

React 19 新特性吐槽&#xff1a;别再整那些花里胡哨的玩意儿了&#xff01; 毒舌时刻 React 19 又双叒叕更新了&#xff0c;一堆新特性看得人眼花缭乱。我就想问一句&#xff1a;这些特性真的是开发者需要的吗&#xff1f;还是 React 团队为了刷存在感整的花架子&#xff1f; …...

使用python给pdf文档自动添加目录书签

1.背景很多时候电子书pdf没有书签目录,阅读起来不方便,于是给它自动加个目录吧2.步骤步骤一:使用ds获取到目录json截图目录,到ds中,然后输入如下提示词:根据目录的图片,提取出如下格式的json目录数据: {"title": "第一章 概述","page": 6,"…...

Harness Engineering 核心概念详解

文章目录1. Harness Engineering 的本质定义1.1 核心定义1.2 诞生的历史时刻1.3 "Harness" 的本意2. Agent Model Harness 核心公式2.1 公式解读2.2 LangChain 工程师的精炼定义2.3 类比&#xff1a;CPU 与操作系统3. Harness 三大支柱详解3.1 支柱一&#xff1a;上…...

OpenClaw飞书机器人实战:千问3.5-9B自动回复消息

OpenClaw飞书机器人实战&#xff1a;千问3.5-9B自动回复消息 1. 为什么选择OpenClaw飞书千问3.5-9B组合&#xff1f; 去年底我开始尝试用AI自动化处理团队沟通需求时&#xff0c;发现市面上大多数方案要么需要将数据上传到第三方平台&#xff0c;要么配置复杂得让人望而却步。…...

c++编程:D进制的A+B(1022-PAT乙级)

1022. D进制的AB#include<bits/stdc.h> using namespace std; int main() { int A, B, D; // 定义三个整数变量 A、B 和进制 Dcin >> A >> B >> D; // 从标准输入读取 A、B、D 的值int sum A B; // 计算…...

车ECU安全刷写(Secure Flashing/Programming)

车 ECU 安全刷写&#xff0c;核心是UDS 协议 安全访问 双分区回滚 供电 / 校验 / 合规全闭环。一、核心基础1. 定义与目标ECU 安全刷写&#xff1a;通过 OBD/CAN/Ethernet&#xff0c;按 ISO14229&#xff08;UDS&#xff09;、ISO15765 标准&#xff0c;对发动机 / 变速箱 …...

哪些降重软件可以同时降低查重率和AIGC疑似率?2026届TOP5硬核评测与选择建议

【CSDN 深度评测 / 突破算法封锁的毕业指南】 近期收到太多在读研究生的私信&#xff1a;“学长&#xff0c;我的论文查重率降到了8%&#xff0c;但教务处系统提示‘AIGC疑似率65%’&#xff0c;被打回重头再来&#xff0c;怎么办&#xff1f;” 在2026年的今天&#xff0c;知网…...