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

news2024/11/26 0:51:14

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
    {
    	// 执行查询语句并返回 DataTable
        public 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;
        }
    
    	// 创建 Command
        private 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.coloradmin.cn/o/1803490.html

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

相关文章

移动端投屏到大屏幕的操作详解

如果你懒得折腾电脑、电视或其他大屏设备上的影视软件安装及配置&#xff0c;可以选择直接在手机端上将影片投屏到电脑、电视或其他大屏设备上&#xff0c;这里给大家分享三种手机投屏的方法。 系统自带的投屏功能 不管是安卓、鸿蒙还是苹果操作系统&#xff0c;都自带了无线…

HTML静态网页成品作业(HTML+CSS)—— 24节气立夏介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

最小相位系统

最小相位系统 1、传递函数 一个线性系统的响应。 比如一个RC低通滤波器&#xff1a; 交流分量在电容的充放电中被滤除掉&#xff0c;通过设置电容器的电容值&#xff0c;以及电阻值&#xff0c;能够控制这种滤除能力&#xff0c;这个参数为RC。 电容的电抗为 1 / j w C 1/j…

变声器软件免费版有哪些?国内外12大热门变声器大盘点!(新)

变声软件是一种人工智能AI音频处理工具&#xff0c;允许用户实时修改自己的声音或改变预先录制的音频。这些软件解决方案可提供不同的效果&#xff0c;如改变声音的音调或速度&#xff0c;或将我们的声音转换成其他人或其他东西的声音&#xff0c;如名人、卡通人物、机器人或不…

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

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

澳大利亚和德国媒体投放-国外新闻发稿-海外软文推广

德国媒体 Firmenpresse德国新闻 Firmenpresse德国新闻是一家备受欢迎的新闻发布平台&#xff0c;其好友搜索引擎在收录网站方面表现出色。如果您希望更好地将您的新闻传播给德国受众&#xff0c;Firmenpresse德国新闻将是一个理想的选择。 Frankfurt Stadtanzeiger法兰克福城…

三维重建 虚拟内窥镜(VE)是什么?怎么实现 使用场景

1.虚拟内窥镜&#xff1a; 就是利用计算机图形学、虚拟现实、图像处理和科学可视化等信息处理技术仿真光学内窥镜对病人进行诊断的一种技术。 VE(Virtual Endoscopy)&#xff0c;虚拟内镜技术。这种CT重建图像可以模拟各种内镜检查的效果&#xff0c;它是假设视线位于所要观察…

RaspAP:轻松实现树莓派无线 AP

RaspAP 是一个可以将树莓派轻松部署成无线 AP&#xff08;Access Point&#xff09;的软件方案&#xff0c;具有一套响应式的 WebUI 来控制 WiFi&#xff0c;用起来和家用路由器一样方便。RaspAP 可以运行在 Raspbian 上&#xff0c;只需要先给树莓派安装好 Raspbian 系统&…

白话解读网络爬虫

网络爬虫&#xff08;Web Crawler&#xff09;&#xff0c;也称为网络蜘蛛、网络机器人或网络蠕虫&#xff0c;是一种自动化程序或脚本&#xff0c;被用来浏览互联网并收集信息。网络爬虫的主要功能是在互联网上自动地浏览网页、抓取内容并将其存储在本地或远程服务器上供后续处…

备战十一届大唐杯国赛预选赛

这次省赛带了太多个省一了&#xff0c;具体可看下面的图片&#xff0c;只放了一部分。目前根据可靠消息&#xff0c;应该还有个预选赛和去年一样&#xff0c;就是还会考一次仿真。如果说通过了就是国二起步然后去北方工业争夺国一国二&#xff0c;没过的话就是国三。 每…

利用GPT和PlantUML快速生成UML图用于设计

在软件开发中&#xff0c;设计阶段可是关键的一步。UML&#xff08;统一建模语言&#xff09;图能帮我们更清晰地理解和规划系统结构&#xff0c;但手动画UML图有时会很费时费力。好消息是&#xff0c;通过结合使用ChatGPT和PlantUML&#xff0c;我们可以高效地生成UML图&#…

最新下载:Hype 4 mac版【软件附加安装教程】

【简介】 Hype是一款强大的Mac OS平台 HTML5 创作工具&#xff0c;它可以在网页上做出赏心悦目的动画效果&#xff0c;创建丰富的网页交互动画&#xff0c;支持层、时间轴等编辑方式&#xff0c;并能很好的导出HTML5/CSS3/JavaScript&#xff0c;在台式机&#xff0c;智能手机…

进口电动低温调节阀的作用-美国NOTON

进口电动低温调节阀在低温环境下的精确控制、广泛的工业应用、高效能设计、耐低温性和密封性、稳定性及可靠性以及安全性等方面发挥着重要作用。 进口电动低温调节阀的作用主要体现在以下几个方面&#xff1a; 低温环境下的精确控制&#xff1a; 进口电动低温调节阀是一种专为…

2024 年最新 Python 基于百度智能云实现短语音识别详细教程

百度智能云语音识别 采用国际领先的流式端到端语音语言一体化建模算法&#xff0c;将语音快速准确识别为文字&#xff0c;支持手机应用语音交互、语音内容分析、机器人对话等场景。百度短语音识别可以将 60 秒以下的音频识别为文字。适用于语音对话、语音控制、语音输入等场景…

Shell以及Shell编程

Shell的任务 ①分析命令&#xff1b; ②处理通配符、变量替换、命令替换、重定向、管道和作业控制&#xff1b; ③搜索命令并执行。 内部命令&#xff1a;内嵌在Shell中。 外部命令&#xff1a;存在于磁盘上的独立可执行文件。 #&#xff01;/bin/bash #! 称为一个幻数&…

微信小程序毕业设计-综合文化信息管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

【开源】医院电子病历管理系统 SSM+JSP+MySQL

目录 一、项目介绍 科室模块 医生模块 预约挂号模块 就诊记录模块 就诊评价模块 二、项目界面 三、核心代码 一、项目介绍 经典老框架SSM打造入门项目《医院电子病历管理系统》&#xff0c;分为用户网页和管理后台&#xff0c;包括科室模块、医生模块、预约挂号模块、…

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

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

10倍速开发开关电源:PSIM DLL集成指南与如何单步调试你的代码

文末有彩蛋哦。 去年提到要写一篇如何在利用PSIM Visual Studio进行仿真联调&#xff0c;加速实际嵌入式端C代码的开发&#xff0c;但因为懒一直没兑现。 本期简单总结下实现的方法。 特别声明&#xff1a;本文约一半以上内容有kimi/文心一言提问式生成&#xff0c;仅用于技…

【数据结构】二叉树:简约和复杂的交织之美

专栏引入&#xff1a; 哈喽大家好&#xff0c;我是野生的编程萌新&#xff0c;首先感谢大家的观看。数据结构的学习者大多有这样的想法&#xff1a;数据结构很重要&#xff0c;一定要学好&#xff0c;但数据结构比较抽象&#xff0c;有些算法理解起来很困难&#xff0c;学的很累…