分享一个 .NET Core Console 项目使用依赖注入的详细例子

image

前言

依赖注入(Dependency Injection,简称DI)是一种软件设计模式,主要用于管理和组织一个软件系统中不同模块之间的依赖关系。

在依赖注入中,依赖项(也称为组件或服务)不是在代码内部创建或查找的,而是由外部系统提供给组件。

具体来说,当某个角色(如一个 C# 实例,调用者)需要另一个角色(如另一个 C# 实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。

但在依赖注入中,创建被调用者的工作不再由调用者来完成,而是由外部容器来完成,并注入给调用者。

依赖注入可以提高代码的可维护性、可测试性、可替换性和可扩展性,降低组件之间的耦合度,使得代码更加清晰和灵活,以前我们写过在 Asp.NET Core Web API 项目中如何通过内置的依赖注入容器使用依赖注入的文章《一个简单的 ASP.NET Core 依赖注入例子,提高代码的可维护性和可扩展性》,今天继续分享一个在 .NET Core Console 项目使用依赖注入的详细例子,大家可以比较两者之间的不同。

Step By Step 步骤

  1. 创建一个 .NET Core Console 项目

  2. 从 Nuget 安装以下包

    Microsoft.Extensions.DependencyInjection
    System.Data.SqlClient

  3. 创建 User 实体类:

    record User(long Id, string UserName, string Password);
    
  4. 创建接口 IUserBiz 和 IUserDAO 及其实现类(留意注释

    interface IUserBiz
    {/// <summary>/// 检查用户名、密码是否匹配/// </summary>/// <param name="userName"></param>/// <param name="password"></param>/// <returns></returns>public bool CheckLogin(string userName, string password);
    }interface IUserDAO
    {/// <summary>/// 查询用户名为userName的用户信息/// </summary>/// <param name="userName"></param>/// <returns></returns>public User? GetByUserName(string userName);
    }class UserBiz : IUserBiz
    {private readonly IUserDAO userDAO;// 通过构造方法要求注入 IUserDAO 服务public UserBiz(IUserDAO userDAO){this.userDAO = userDAO;}public bool CheckLogin(string userName, string password){var user = userDAO.GetByUserName(userName);if (user == null){return false;}else{return user.Password == password;}}
    }class UserDAO : IUserDAO
    {private readonly IDbConnection conn;// 通过构造方法要求依赖注入容器为其注入一个 IDbConnection 对象public UserDAO(IDbConnection conn){this.conn = conn;}public User? GetByUserName(string userName){using var dt = SqlHelper.ExecuteQuery(conn, $"select * from T_Users where UserName={userName}");if (dt.Rows.Count <= 0){return null;}DataRow row = dt.Rows[0];int id = (int)row["Id"];string uname = (string)row["UserName"];string password = (string)row["Password"];return new User(id, uname, password);}
    }	
    
  5. 创建数据库操作帮助类 SqlHelper

    using System.Data;static class SqlHelper
    {// 执行查询语句并返回 DataTablepublic static DataTable ExecuteQuery(this IDbConnection conn, FormattableString formattable){using IDbCommand cmd = CreateCommand(conn, formattable);DataTable dt = new DataTable();using var reader = cmd.ExecuteReader();dt.Load(reader);return dt;}// 执行查询语句并返回一个值public static object? ExecuteScalar(this IDbConnection conn, FormattableString formattable){using IDbCommand cmd = CreateCommand(conn, formattable);return cmd.ExecuteScalar();}// 执行 DML 语句public static int ExecuteNonQuery(this IDbConnection conn, FormattableString formattable){using IDbCommand cmd = CreateCommand(conn, formattable);int result = cmd.ExecuteNonQuery();return result;}// 创建 Commandprivate static IDbCommand CreateCommand(IDbConnection conn, FormattableString formattable){var cmd = conn.CreateCommand();string sql = formattable.Format;for (int i = 0; i < formattable.ArgumentCount; i++){sql = sql.Replace("{" + i + "}", "@p" + i);var parameter = cmd.CreateParameter();parameter.ParameterName = "@p" + i;parameter.Value = formattable.GetArgument(i);cmd.Parameters.Add(parameter);}cmd.CommandText = sql;return cmd;}
    }
    
  6. 打开 Program.cs,引入依赖注入命名空间

    using Microsoft.Extensions.DependencyInjection;
    
  7. 创建依赖注入容器

    // 2. 创建用于注册服务的容器
    ServiceCollection services = new ServiceCollection();
    ``
  8. 注入服务(留意注释

    // 3.1 注入 IDbConnection 服务(范围)
    services.AddScoped<IDbConnection>(sp => {string connStr = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true";var conn = new SqlConnection(connStr);conn.Open();return conn;
    });// 3.2 注入 IUserDAO 和 IUserBiz 服务(范围)
    // ----把UserDAO注册为IUserDAO服务的实现类
    // ----实现类的参数也会一起注入
    services.AddScoped<IUserDAO, UserDAO>();
    services.AddScoped<IUserBiz, UserBiz>();	
    
  9. 使用(留意注释

    // 调用 IServiceCollection 的 BuildServiceProvider 方法创建一个 ServiceProvider 对象
    using (ServiceProvider sp = services.BuildServiceProvider())
    {// 调用 GetRequiredService 方法获取服务var userBiz = sp.GetRequiredService<IUserBiz>();bool b = userBiz.CheckLogin("jacky", "123456");Console.WriteLine(b);
    }
    

结语

依赖注入的实现方式有多种,如构造注入、属性注入和接口注入等。

通过依赖注入,可以更容易地管理和维护系统的各个组件,轻松地将模拟依赖注入到单元测试中,更灵活地添加新功能或替换现有组件。

虽然依赖注入在软件开发中有很多优点,但在使用时也需要谨慎,以确保正确地管理和配置依赖关系,避免潜在的问题,比如违背单一职责原则等设计原则,导致代码结构混乱,维护成本增加等。

附录:完整的 Program.cs 代码(留意注释

using DI魅力渐显_依赖注入;// 1. 引用依赖注入命名空间
using Microsoft.Extensions.DependencyInjection;
using System.Data;
using System.Data.SqlClient;// 2. 创建用于注册服务的容器
ServiceCollection services = new ServiceCollection();// 3.1 注入 IDbConnection 服务(范围)
services.AddScoped<IDbConnection>(sp => {string connStr = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;MultipleActiveResultSets=true";var conn = new SqlConnection(connStr);conn.Open();return conn;
});// 3.2 注入 IUserDAO 和 IUserBiz 服务(范围)
// ----把UserDAO注册为 IUserDAO 服务的实现类
// ----实现类的参数也会一起注入
services.AddScoped<IUserDAO, UserDAO>();
services.AddScoped<IUserBiz, UserBiz>();// 4. 使用
// 调用 IServiceCollection 的 BuildServiceProvider 方法创建一个 ServiceProvider 对象
using (ServiceProvider sp = services.BuildServiceProvider())
{// 调用 GetRequiredService 方法获取服务var userBiz = sp.GetRequiredService<IUserBiz>();bool b = userBiz.CheckLogin("jacky", "123456");Console.WriteLine(b);
}

我是老杨,一个奋斗在一线的资深研发老鸟,让我们一起聊聊技术,聊聊人生。

都看到这了,求个点赞、关注、在看三连呗,感谢支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/344491.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elastic Search(ES)Java 入门实操(3)数据同步

基本概念和数据查询代码&#xff1a; Elastic Search &#xff08;ES&#xff09;Java 入门实操&#xff08;1&#xff09;下载安装、概念-CSDN博客 Elastic Search&#xff08;ES&#xff09;Java 入门实操&#xff08;2&#xff09;搜索代码-CSDN博客 想要使用 ES 来查询数…

【全开源】云调查考试问卷系统(FastAdmin+ThinkPHP+Uniapp)

便捷、高效的在线调研与考试新选择​ 云调查考试问卷是一款基于FastAdminThinkPHPUniapp开发的问卷调查考试软件&#xff0c;可以自由让每一个用户自由发起调查问卷、考试问卷。发布的问卷允许控制问卷的搜集、回答等各个环节的设置&#xff0c;同时支持系统模板问卷&#xff…

【优选算法】字符串

一、相关编程题 1.1 最长公共前缀 题目链接 14. 最长公共前缀 - 力扣&#xff08;LeetCode&#xff09; 题目描述 算法原理 编写代码 // 解法一&#xff1a;两两比较 class Solution { public:string longestCommonPrefix(vector<string>& strs) {int k strs[0…

vscode+latex设置跳转快捷键

安装参考 https://blog.csdn.net/Hacker_MAI/article/details/130334821 设置默认recipe ctrl P 打开设置&#xff0c;搜索recipe 也可以点这里看看有哪些配置 2 设置跳转快捷键

【python报错】TypeError: dict.get() takes no keyword arguments

【Python报错】TypeError: dict.get() takes no keyword arguments 在Python中&#xff0c;字典&#xff08;dict&#xff09;是一种非常灵活的数据结构&#xff0c;用于存储键值对。dict.get()方法是用来从字典中获取与给定键&#xff08;key&#xff09;相关联的值&#xff0…

[MQTT]服务器EMQX搭建SSL/TLS连接过程(wss://)

&#x1f449;原文阅读 &#x1f4a1;章前提示 本文采用8084端口进行连接&#xff0c;是EMQX 默认提供了四个常用的监听器之一&#xff0c;如果需要添加其他类型的监听器&#xff0c;可参考官方文档&#x1f517;管理 | EMQX 文档。 本文使用自签名CA&#xff0c;需要提前在L…

【转】ES, 广告索引

思考&#xff1a; 1&#xff09;直接把别名切换到上一个版本索引 --解决问题 2&#xff09;广告层级索引如何解决&#xff1f; -routing、join 3&#xff09;查询的过程&#xff1a;query and fetch, 优化掉fetch 4&#xff09;segment合并策略 5&#xff09;全量写入时副…

17、matlab实现均值滤波、中值滤波、Butterworth滤波和线性相位FIR滤波

1、创建信号 1&#xff09;创建正余弦信号、噪声信号和混合信号 原始正余弦信号公式&#xff1a;Signal1 sin(2*pi*20* t) sin(2*pi*40* t) sin(2*pi*60* t) 高斯分布的白噪声&#xff1a;NoiseGauss [randn(1,2000)] 均匀分布的白噪声&#xff1a;[rand(1,2000)] 正余弦…

数据库管理-第198期 升级Oracle ACE Pro,新赛季继续努力(20240605)

数据库管理198期 2024-06-05 数据库管理-第198期 升级ACE Pro&#xff0c;新赛季继续努力&#xff08;20240605&#xff09;1 惊喜2 变化3 Oracle ACE总结 数据库管理-第198期 升级ACE Pro&#xff0c;新赛季继续努力&#xff08;20240605&#xff09; 作者&#xff1a;胖头鱼的…

【MySQL数据库】my.ini文件参数中文注释

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

【JavaScript】内置对象 - 字符串对象 ④ ( 根据索引位置返回字符串中的字符 | 代码示例 )

文章目录 一、根据索引位置返回字符串中的字符1、charAt 函数获取字符2、charCodeAt 函数获取字符 ASCII 码3、数组下标获取字符 String 字符串对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String 一、根据索引位置返回…

React Hooks 封装可粘贴图片的输入框组件(wangeditor)

需求是需要一个文本框 但是可以支持右键或者ctrlv粘贴图片&#xff0c;原生js很麻烦&#xff0c;那不如用插件来实现吧~我这里用的wangeditor插件&#xff0c;初次写初次用&#xff0c;可能不太好&#xff0c;但目前是可以达到实现需求的一个效果啦&#xff01;后面再改进吧~ …

【NI国产替代】500 MSPS 采样率,14 bit 分辨率数据采集盒子

• 双高速高精度数据采集通道 • 支持内外精准触发采样模式 • 丰富的总线控制接口 • 抗干扰能力强 高速采集盒子是一款双通道&#xff0c;具有 500 MSPS 采样率&#xff0c;14 bit 分辨率的高速高精度数据采集设备&#xff0c;其模拟输入带宽为 200 MHz&#xff0c;…

278 基于Matlab GUI的中重频PD雷达仿真系统

基于Matlab GUI的中重频PD雷达仿真系统。具有26页文档报告。仿真雷达信号的发射、传播、散射、接收、滤波、信号处理、数据处理的全部物理过程&#xff0c;因此应当实现对雷达发射机、天线、接收机、回波信号处理、数据处理的建模与仿真。程序已调通&#xff0c;可直接运行。 2…

【启程Golang之旅】让文件操作变得简单

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

C++STL简介

一、STL介绍 STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 二、STL的版本 1、原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完…

二叉树的实现(初阶数据结构)

1.二叉树的概念及结构 1.1 概念 一棵二叉树是结点的一个有限集合&#xff0c;该集合&#xff1a; 1.或者为空 2.由一个根结点加上两棵别称为左子树和右子树的二叉树组成 从上图可以看出&#xff1a; 1.二叉树不存在度大于2的结点 2.二叉树的子树有左右之分&#xff0c;次序不能…

造假高手——faker

在测试写好的代码时通常需要用到一些测试数据&#xff0c;大量的真实数据有时候很难获取&#xff0c;如果手动制造测试数据又过于繁重无聊&#xff0c;显得不够优雅&#xff0c;今天我们介绍的faker这个轮子可以完美的解决这个问题。faker是一个用于生成各种类型假数据的库&…

C++STL初阶(3):string模拟实现的完善

1.流提取>>的优化&#xff08;利用缓存区的思想&#xff09; istream& operator>>(istream& is,string& str) {str.clear();char c;c is.get();while (c ! \0 && c ! \n) {str c;c is.get();}return is; } 在上文的对string的实践中&#…

Android Lottie 体积优化实践:从 6.4 MB 降到 530 KB

一、说明 产品提出需求&#xff1a;用户有 8 个等级&#xff0c;每个等级对应一个奖牌动画。 按照常用的实现方式&#xff1a; 设计提供 8 个 lottie 动画&#xff08;8 个 json 文件&#xff09;。研发将 json 文件打包进入 APK 中。根据不同等级播放指定的动画。 每一个 …