分享一个 .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.mzph.cn/pingmian/24839.shtml

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

相关文章

二叉树的算法题目

二叉树的遍历题目 二叉树遍历一般包含三种分别为&#xff1a;根左右、左根右、左右根&#xff08;又称为前序遍历、中序遍历、后序遍历&#xff09; 方法一&#xff1a;使用递归遍历 方法二&#xff1a;使用迭代使用栈 我们以左根右&#xff08;中序遍历&…

【SpringBoot】项目搭建基本步骤(整合 Mybatis)

搭建 SpringBoot 项目有两种方式&#xff1a;使用 IDEA、或者在 Spring 官网下载。 1. IDEA 创建 打开 IDEA 后&#xff0c;英文版请点击 File -> New -> Project -> Spring Initialer。 中文版请点击 文件 -> 新建 -> 项目 -> Spring Initialer。 在打开的…

【Proteus8.16】Proteus8.16.SP3.exe的安装包,安装方法

下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/14ZlETF7g4Owh8djLaHwBOw?pwd2bo3 提取码&#xff1a;2bo3 管理员打开proteus8.16.SP3.exe一路装就行了&#xff0c;许可证选Licence2.lxk,点安装后关闭&#xff0c;然后继续装完。 然后打开Patch-Proteus-8.16-…

【Ardiuno】ESP32单片机初试点亮LED小灯

之前用的Ardiuno的主板做过一些简单的开发实验&#xff0c;按照相关说明还是很容易进行操作的。最近看了ESP32可以有wifi的功能&#xff0c;也就买来实验一下。 ESP32的主板开发环境安装&#xff0c;按照说明的安装下载程序总是报错&#xff0c;又上网搜索半天最后按照CSDN上某…

平衡二叉树详解

目录 平衡二叉树的定义 平衡二叉树的基本操作 查找 插入 AVL树的建立 平衡二叉树的定义 平衡二叉树仍然是一棵二叉查找树&#xff0c;只是在其基础上增加了平衡的要求&#xff0c;也就是其左右子树的高度之差的绝对值不超过1。 在定义树的结构时需要加入一个变量height&…

uc_os操作练习

目录 一、CubeMX配置 二、获取uc-os源码 三、代码移植 四、代码修改 五、总结 六、参考资料 一、CubeMX配置 首先进入CubeMX&#xff0c;&#xff0c;新建工程&#xff0c;选择STM32F103C8T6芯片&#xff0c;照例配置好RCC和SYS。 然后配置GPIO输出&#xff0c;这里选择P…

2024 年最新 Python 基于百度智能云实现文字识别 OCR 详细教程

文字识别 OCR 概述 文字识别OCR&#xff08;Optical Character Recognition&#xff09;提供多场景、多语种、高精度的文字检测与识别服务&#xff0c;多项ICDAR指标居世界第一。广泛适用于金融服务、财税报销、法律政务、保险医疗、快递物流、交通出行、教育培训等场景&#…

C++ 11 【线程库】【包装器】

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;C修炼之路⏪   &#x1f69a;代码仓库:C高阶&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C知识   &#x1f51d;&#x1f51d; 目录 前言 一、thread类的简单介绍 get_id…

BeagleBone Black入门总结

文章目录 参考连接重要路径系统镜像下载访问 BeagleBone 参考连接 镜像下载启动系统制作&#xff1a;SD卡烧录工具入门书籍推荐&#xff1a;BeagleBone cookbookBeagleBone概况&#xff1f; 重要路径 官方例程及脚本路径&#xff1a;/var/lib/cloud9 系统镜像下载 疑问&am…

C 语言实现在终端里输出二维码

Mac 环境安装二维码库 brew install qrencode安装过程报权限问题执行以下命令 sudo chown -R 用户名 /usr/local/include /usr/local/lib chmod uw /usr/local/include /usr/local/lib#include <stdio.h> #include <qrencode.h>void print_qr_code(QRcode *qrcode…

SpringBoot+Vue图书管理系统(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 用户管理员 功能截图

人工智能在交通与物流领域的普及及应用

文章目录 &#x1f40b;引言 &#x1f40b;自动驾驶 &#x1f988;自动驾驶汽车 &#x1f421;应用现状 &#x1f421;技术实现 &#x1f421;实现过程及代码 &#x1f40b;智能交通管理 &#x1f988;应用现状 &#x1f988;技术实现 &#x1f988;实现过程及代码 &…

老黄一举揭秘三代GPU!打破摩尔定律,打造AI帝国,量产Blackwell解决ChatGPT全球耗电难题

近日&#xff0c;老黄手持Blackwell向全世界展示的那一刻&#xff0c;全场观众沸腾了。 这是迄今为止世界上最大的芯片&#xff01; 用老黄的话来说&#xff0c;它是「全世界迄今为止制造出来的最复杂、性能最高的计算机。」GPT-4o深夜发布&#xff01;Plus免费可用&#xff01…

结构体(1)<C语言>

导言 结构体是C语言中的一种自定义类型&#xff0c;它的值&#xff08;成员变量&#xff09;可以是多个&#xff0c;且这些值可以为不同类型&#xff0c;这也是和数组的主要区别&#xff0c;下面将介绍它的一些基本用法&#xff0c;包括&#xff1a;结构体的创建、结构体变量的…

【Vue】Vue路由-重定向

问题 网页打开时&#xff0c; url 默认是 / 路径&#xff0c;未匹配到组件时&#xff0c;会出现空白 解决方案 重定向 → 匹配 / 后, 强制跳转 /home 路径 语法 { path: 匹配路径, redirect: 重定向到的路径 }, 比如&#xff1a; { path:/ ,redirect:/home }代码示例 const…

应用广义线性模型二|二响应广义线性模型

系列文章目录 文章目录 系列文章目录一、二响应模型的不同表达方式和响应函数二、二响应模型的性质&#xff08;一&#xff09;二响应变量的条件数学期望与方差&#xff08;二&#xff09;二响应模型参数的极大似然估计&#xff08;三&#xff09;二响应模型的优势 三、二响应模…

如何在Windows 11中恢复丢失的快速访问菜单?这里提供解决办法

序言 在电脑的“快速访问”菜单中找不到固定的项目?或者,整个菜单对你来说已经消失了吗?无论哪种方式,你都可以强制你的电脑恢复菜单并显示其中的所有项目。以下是如何在你的Windows 11电脑上做到这一点。 将文件资源管理器设置为打开到主页 当你在文件资源管理器的左侧…

分享飞行棋夫妻互动游戏高阶版,揭秘夫妻飞行棋游戏玩法!

朋友们&#xff0c;今天我要给你们介绍一款超级甜蜜的小游戏——情侣飞行棋。别小看它&#xff0c;这可不是咱们小时候玩的那种&#xff0c;这是专门为咱们这些恩爱的小两口设计的&#xff0c;能让你们的感情在游戏中更加甜蜜蜜&#xff0c;擦出更多爱的火花。 准备好了吗&…

力扣96 不同的二叉搜索树 Java版本

文章目录 题目描述代码 题目描述 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 示例 2&#xff1a; 输入…

鸿蒙低代码开发一个高频问题

在版本是DevEco Studio 3.1.1 Release&#xff0c;SDK是3.1.0(API9)。 创建和设计的visual文件经常会遇到无法渲染的情况&#xff0c;或者自定义组件在Custom列表中突然不见了的情况。 有以下报错信息的&#xff1a; JSON schema validation error: data/visualModel/value/…