C#.NET 依賴注入詳解

一、是什么??

????????在 C#.NET 中,依賴注入(Dependency Injection,簡稱 DI) 是一種設計模式,用于實現控制反轉(Inversion of Control,IoC),以降低代碼耦合、提高可測試性和可維護性。

????????依賴注入是將一個對象的依賴(即它所需的其他對象或服務)通過外部提供(注入)的方式傳遞給它,而不是由對象自身創建或查找依賴。

????????其核心思想是將對象的創建和依賴管理交給容器(IoC 容器),從而解耦代碼。DI 是現代 .NET 開發(尤其是 ASP.NET Core)的核心特性之一,廣泛應用于企業級應用。

一個生活化的比喻:想象一下,你想喝一杯咖啡。

?沒有依賴注入的做法

你親自去買咖啡豆,親自找來磨豆機,親自燒水,親自操作咖啡機,最后做出一杯咖啡。在這個過程中,你(這個對象)強依賴咖啡豆磨豆機咖啡機等具體事物。如果明天你想換個牌子的咖啡豆,或者磨豆機壞了要換新的,你就得親自去修改整個流程(修改你的代碼)。

??有依賴注入的做法

你走進一家咖啡店,對服務員說:“來一杯拿鐵”。你并不關心咖啡豆是哪個莊園的,用的是什么牌子的咖啡機。服務員(?“注入器”?)會把所有你需要的東西(依賴項)準備好,然后把一杯完美的拿鐵(咖啡這個對象)?“注入”?到你手中。

在這個比喻中:

  • :就是我們的?客戶端(Client)?,即需要使用其他服務的類。
  • 咖啡:就是?服務(Service)?,即被客戶端使用的依賴對象。
  • “來一杯拿鐵”這個動作:就是客戶端聲明它需要一個服務。
  • 服務員:就是?依賴注入容器(DI Container)?,它負責創建和管理服務的實例,并將其提供給客戶端。

核心思想:一個類(你)不應該自己動手創建它所依賴的對象(咖啡)。相反,它應該在被創建的時候,由外部(服務員)將這些依賴關系傳遞(注入)給它。

這種思想,叫做“控制反轉”(Inversion of Control, IoC)。而依賴注入(DI)是實現控制反轉最常見的一種設計模式。

二、為什么

依賴注入帶來的好處

如果我們不使用 DI,代碼通常會像這樣(緊密耦合):

public class NotificationService
{private readonly SmsSender _smsSender;public NotificationService(){// 問題所在:NotificationService 強行依賴了【具體】的 SmsSender 類// 它自己負責創建這個依賴項_smsSender = new SmsSender(); }public void SendNotification(string message){_smsSender.Send(message);}
}

這段代碼有什么問題?

  1. 不靈活:如果明天產品經理說,我們也要支持郵件通知。你就必須修改?NotificationService?的內部代碼,加入?EmailSender,甚至可能要添加復雜的?if/else?來決定用哪個。
  2. 難測試:在進行單元測試時,你無法輕易地把?SmsSender?換成一個“假的”發送器(Mock對象)。你測試?NotificationService?的時候,可能會真的發送一條短信出去,這既浪費資源又不是我們想要的結果。

使用了依賴注入后,代碼會變得(松散耦合)?:

第1步:定義一個“標準”接口

我們不關心具體是短信還是郵件,只關心它有沒有一個“發送”的功能。

// 定義一個服務接口(標準)
public interface IMessageSender
{void Send(string message);
}

第2步:創建具體的服務實現

// 短信發送器
public class SmsSender : IMessageSender
{public void Send(string message){Console.WriteLine($"通過短信發送: {message}");}
}// 郵件發送器
public class EmailSender : IMessageSender
{public void Send(string message){Console.WriteLine($"通過郵件發送: {message}");}
}

第3步:改造客戶端,讓它依賴于“標準”而非“具體”

public class NotificationService
{private readonly IMessageSender _sender;// 重點:依賴項通過構造函數被【注入】進來// NotificationService 不再關心 _sender 到底是短信還是郵件,它只知道這個東西能發消息public NotificationService(IMessageSender sender){_sender = sender;}public void SendNotification(string message){_sender.Send(message);}
}

第4步:主程序調用

依賴注入(DI): 在創建 NotificationService 實例時,我們在構造函數中傳入了 SmsSender 的實例,而不是讓 NotificationService 自己創建這個實例。這種方式被稱為依賴注入(DI)。通過 DI,我們可以輕松地將不同的 IMessageSender 實現(如 EmailSender)注入到 NotificationService 中,從而實現了代碼的解耦和靈活性

static void Main(string[] args)
{NotificationService service = new NotificationService(new SmsSender());//想通過郵件發送只需更改傳入的實例 如://NotificationService service = new NotificationService(new EmailSender());service.SendNotification("Hello, world!");Console.ReadKey();}

這樣做的好處顯而易見:

  1. 松散耦合 (Loose Coupling)?:NotificationService?只依賴于?IMessageSender?接口,而不再是某個具體的發送類。你可以輕松地換成?EmailSenderPushSender?或任何實現了?IMessageSender?接口的類,而無需修改?NotificationService?的任何代碼。
  2. 易于測試 (Increased Testability)?:測試時,我們可以輕松地創建一個?MockMessageSender?類,并將其注入到?NotificationService?中,從而可以在不依賴任何外部服務的情況下獨立測試其邏輯。
  3. 代碼更清晰、更易維護 (Better Code Organization)?:職責分離,NotificationService?只負責業務邏輯,而對象的創建和組裝則交給了外部的 DI 容器。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91168.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91168.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91168.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue監視數據的原理和set()的使用

在 Vue 中,Vue.set()(或 this.$set())是用于解決響應式數據更新檢測的重要方法,其底層與 Vue 的數據監視原理緊密相關。以下從使用場景和實現原理兩方面詳細說明:一、Vue.set () 的使用場景與用法1. 為什么需要 Vue.se…

在 Vue 中,如何在回調函數中正確使用 this?

在 Vue 組件中,this 指向當前組件實例,但在回調函數(如定時器、異步請求、事件監聽等)中,this 的指向可能會丟失或改變,導致無法正確訪問組件的屬性和方法。以下是在回調函數中正確使用 this 的幾種常見方式…

第4章唯一ID生成器——4.4 基于數據庫的自增主鍵的趨勢遞增的唯一ID

基于數據庫的自增主鍵也可以生成趨勢遞增的唯一 ID,且由于唯一ID不與時間戳關聯,所以不會受到時鐘回撥問題的影響。 4.4.1 分庫分表架構 數據庫一般都支持設置自增主鍵的初始值和自增步長,以MySQL為例,自增主鍵的自增步長由auto_i…

設計模式:Memento 模式詳解

Memento 模式詳解Memento(備忘錄)模式是一種行為型設計模式,用于在不破壞封裝性的前提下,捕獲并外部化一個對象的內部狀態,以便在之后能夠將該對象恢復到原先保存的狀態。它廣泛應用于需要實現撤銷(Undo&am…

數據結構(6)單鏈表算法題(下)

一、環形鏈表Ⅰ 1、題目描述 https://leetcode.cn/problems/linked-list-cycle 2、算法分析 思路:快慢指針 根據上圖所示的流程,我們可以推測出這樣一個結論:若鏈表帶環,快慢指針一定會相遇。 那么,這個猜測是否正…

智能制造,從工廠建模,工藝建模,柔性制造,精益制造,生產管控,庫存,質量等多方面講述智能制造的落地方案。

智能制造,從工廠建模,工藝建模,柔性制造,精益制造,生產管控,庫存,質量等多方面講述智能制造的落地方案。

Qt 分裂布局:QSplitter 使用指南

在 GUI 開發中,高效管理窗口空間是提升用戶體驗的關鍵。QSplitter 作為 Qt 的核心布局組件,讓動態分割窗口變得簡單直觀。一、QSplitter 核心功能解析 QSplitter 是 Qt 提供的布局管理器,專用于創建可調節的分割區域: 支持水平/垂…

R語言與作物模型(DSSAT模型)技術應用

R語言在DSSAT模型的氣候、土壤、管理措施等數據準備,自動化模擬和結果分析上都發揮著重要的作用。一:DSSAT模型的高級應用 1.作物模型的概念 2.DSSAT模型發展現狀 3.DSSAT與R語言的安裝 4.DSSAT模型的高級應用案例 5.R語言在作物模型參數優化中的應用 6.…

JavaSE:學習輸入輸出編寫簡單的程序

一、打印輸出到屏幕 Java提供了三種核心輸出方法,適合不同場景: System.out.println() 打印內容后 自動換行 System.out.println("Welcome"); System.out.println("to ISS"); // 輸出: // Welcome // to ISSSystem.out…

訪問者模式感悟

訪問者模式 首先有兩個東西: 一個是訪問者vistor (每一個訪問者類都代表了一類操作) 一個是被訪問者entity (model /info/pojo/node等等這些都行)也就是是說是一個實體類 其操作方法被抽離給了其他類。 訪問者模式的核心思想就是**“把操作從數據結構中分離出來,每種操作…

從零到部署:基于Go和Docker的全棧短鏈接服務實戰(含源碼)

摘要:本文將手把手帶你使用Go語言,并遵循依賴倒置、分層架構等最佳實踐,構建一個高性能、高可用的全棧短鏈接生成器。項目采用Echo框架、GORM、Redis、MySQL,并通過Docker和Docker Compose實現一鍵式容器化部署到阿里云服務器。文…

MyBatis_3

上一篇文章,我們學習了使用XML實現MyBatis進行增、刪、查、改等操作,本篇文章,我們將學習#{ }和${ }獲取方法參數的區別和使用MyBatisXML實現動態SQL語句。 #{ }和${ }的區別 在之前的文章中我們都是使用#{ }進行賦值,但實際上M…

智能圖書館管理系統開發實戰系列(一):項目架構設計與技術選型

項目背景 智能圖書館管理系統(ILMS)是一個現代化的桌面應用程序,采用前后端分離架構,結合了Web技術的靈活性和桌面應用的用戶體驗。本項目從高保真原型設計開始,經過完整的軟件開發生命周期,最終實現為一個…

應急前端“黃金3分鐘”設計:極端場景下的操作界面極速搭建技術

摘要**地震突發,應急指揮系統的操作界面卻因加載緩慢無法及時調取數據;火災現場,消防員手持終端的操作步驟繁瑣,延誤救援時機。在分秒必爭的極端場景中,傳統前端操作界面為何頻頻 “掉鏈子”?怎樣才能在 “…

【Android】三種彈窗 Fragment彈窗管理

三三要成為安卓糕手 零:布局轉換 在很多工程當中用的都是LinearLayout和relativelayout,這兩者都可以轉化為Constrainlayout 注:這種用法并不能精確轉換,具體還是要根據自己的需求來做布局約束一:snackbar顯示彈窗 ((2…

【AI繪畫】Stable Diffusion webUI 與 ComfyUI 全解析:安裝、模型、插件及功能對比

一、Stable Diffusion 與 UI 工具概述 Stable Diffusion 是當前最主流的開源 AI 繪畫模型,通過文本描述生成高質量圖像。為降低使用門檻,開發者推出了多種圖形界面(UI)工具,其中AUTOMATIC1111 webUI(簡稱 …

ABP VNext + GraphQL Federation:跨微服務聯合 Schema 分層

ABP VNext GraphQL Federation:跨微服務聯合 Schema 分層 🚀 在微服務架構下,服務之間往往需要相互通信,而 GraphQL Federation 提供了一個有效的解決方案,幫助我們將多個微服務的 GraphQL API 聚合成一個統一的入口…

小程序組件的生命周期,以及在小程序中進行接口請求的方法設置

微信小程序組件生命周期與接口請求方法詳解一、小程序組件生命周期微信小程序組件的生命周期指的是組件在不同階段自動觸發的函數,開發者可以利用這些鉤子函數在特定時機執行相應操作。小程序組件的生命周期主要分為兩類:組件自身生命周期和組件所在頁面…

在線游戲玩家與物品交互處理

玩家與物品接觸后的判定if (hit ! null && hit.CompareTag("Item")){Debug.Log("撿東西");var worldItem hit.gameObject.GetComponent<WorldItem>();if (worldItem ! null){var inventory GetComponent<PlayerInventory>();if (inv…

深入解析Java Stream 構建:AbstractPipeline

Java Stream 宏觀介紹見&#xff1a;深入解析 Java Stream 設計&#xff1a;從四幕劇看流水線設計與執行機制-CSDN博客 PipelineHelper PipelineHelper 是 Java Stream API 內部一個至關重要的輔助類。正如其名&#xff0c;它是一個“管道助手”。可以把它想象成一個執行上下文…