最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#中控制反轉(zhuǎn)和依賴注入原理及實現(xiàn)

 更新時間:2025年11月17日 10:14:20   作者:YuanlongWang  
本文深入探討了IoC(控制反轉(zhuǎn))和DI(依賴注入)的概念,及在面向?qū)ο缶幊讨械膽?yīng)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

控制反轉(zhuǎn)(IoC)和依賴注入(DI)是面向?qū)ο缶幊讨薪鉀Q對象依賴關(guān)系的核心設(shè)計思想,目的是降低代碼耦合度,提高可維護性和可測試性。下面從概念、關(guān)系、實現(xiàn)原理到代碼示例逐步說明。

一、控制反轉(zhuǎn)(IoC:Inversion of Control)

概念

控制反轉(zhuǎn)是一種設(shè)計原則,核心是 “反轉(zhuǎn)對象的創(chuàng)建和依賴管理的控制權(quán)”:

  • 傳統(tǒng)程序中,對象的創(chuàng)建和依賴關(guān)系(如 A 依賴 B,A 會直接new B())由對象自身控制(主動創(chuàng)建依賴)。
  • IoC 原則下,這種控制權(quán)被 “反轉(zhuǎn)” 給外部容器(如 IoC 容器),對象只需聲明自己需要什么依賴,由容器負(fù)責(zé)創(chuàng)建并 “推送” 依賴給它(被動接收依賴)。

舉個生活例子

  • 傳統(tǒng)方式:你(對象 A)想吃漢堡,需要自己買菜、做面包、煎肉餅(自己創(chuàng)建所有依賴)。
  • IoC 方式:你(對象 A)只需告訴餐廳(容器)“我要漢堡”,餐廳負(fù)責(zé)準(zhǔn)備所有材料并做好漢堡給你(容器創(chuàng)建并提供依賴)。

二、依賴注入(DI:Dependency Injection)

概念

依賴注入是實現(xiàn) IoC 原則的具體方式,核心是 “將對象的依賴通過外部傳遞(注入)給它,而非對象自己創(chuàng)建”。簡單說:依賴注入 = 誰依賴誰 + 誰注入誰 + 注入什么

  • “誰依賴誰”:應(yīng)用程序中的對象(如 Service)依賴于其他對象(如 Repository)。
  • “誰注入誰”:IoC 容器將依賴對象注入到被依賴對象中。
  • “注入什么”:被依賴的具體實現(xiàn)(如UserRepository注入到UserService)。

IoC 與 DI 的關(guān)系

  • IoC 是設(shè)計原則(目標(biāo)):反轉(zhuǎn)控制權(quán),解耦依賴。
  • DI 是實現(xiàn)手段(方法):通過注入的方式實現(xiàn) IoC??梢岳斫鉃椋?ldquo;IoC 是思想,DI 是技術(shù)”。

三、實現(xiàn)原理

IoC/DI 的核心是IoC 容器(如 C# 中的 Autofac、Unity 等),其工作流程可分為 3 步:

  • 注冊(Register):告訴容器 “某個接口(抽象)對應(yīng)哪個具體實現(xiàn)類”。例如:container.Register<ILogger, FileLogger>() 表示 “ILogger接口由FileLogger類實現(xiàn)”。
  • 解析(Resolve):當(dāng)需要某個對象時,容器根據(jù)注冊信息,通過反射創(chuàng)建對象,并自動解析其依賴關(guān)系。
  • 注入(Inject):容器將解析出的依賴對象,通過構(gòu)造函數(shù)、屬性或方法等方式,注入到目標(biāo)對象中。

四、C# 代碼示例

下面通過 “用戶服務(wù)(UserService)依賴日志組件(ILogger)” 的場景,對比傳統(tǒng)方式和 DI 方式的區(qū)別,并模擬一個簡單的 IoC 容器。

1. 傳統(tǒng)方式(無 IoC/DI):緊耦合

// 日志接口
public interface ILogger
{
    void Log(string message);
}

// 日志實現(xiàn)(文件日志)
public class FileLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"[FileLogger] {message}");
    }
}

// 用戶服務(wù)(依賴ILogger)
public class UserService
{
    // 傳統(tǒng)方式:自己創(chuàng)建依賴(緊耦合!如果要換數(shù)據(jù)庫日志,必須修改這里)
    private ILogger _logger = new FileLogger(); 

    public void AddUser(string username)
    {
        // 業(yè)務(wù)邏輯:添加用戶
        _logger.Log($"用戶 {username} 已添加"); // 使用日志
    }
}

// 調(diào)用
class Program
{
    static void Main()
    {
        UserService userService = new UserService();
        userService.AddUser("張三"); 
        // 輸出:[FileLogger] 用戶 張三 已添加
    }
}

問題

  • UserService直接依賴FileLogger(具體實現(xiàn)),而非ILogger(抽象),違反 “依賴倒置原則”。
  • 若要替換日志實現(xiàn)(如改為DatabaseLogger),必須修改UserService的代碼,耦合度極高,難以維護和測試。

2. 依賴注入(DI)方式:松耦合

通過構(gòu)造函數(shù)注入(最常用的注入方式),將依賴從外部傳遞給UserService

// 新增一個數(shù)據(jù)庫日志實現(xiàn)
public class DatabaseLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine($"[DatabaseLogger] {message}");
    }
}

// 修改UserService:通過構(gòu)造函數(shù)接收依賴(依賴抽象,不依賴具體實現(xiàn))
public class UserService
{
    private ILogger _logger;

    // 構(gòu)造函數(shù)注入:依賴由外部傳入,而非自己創(chuàng)建
    public UserService(ILogger logger)
    {
        _logger = logger; // 接收注入的日志對象
    }

    public void AddUser(string username)
    {
        _logger.Log($"用戶 {username} 已添加");
    }
}

// 調(diào)用:手動注入依賴(簡單場景下可手動管理,復(fù)雜場景用容器)
class Program
{
    static void Main()
    {
        // 1. 創(chuàng)建依賴對象(可替換為DatabaseLogger)
        ILogger logger = new FileLogger(); 
        // ILogger logger = new DatabaseLogger(); 

        // 2. 注入到UserService
        UserService userService = new UserService(logger); 
        userService.AddUser("張三"); 
        // 輸出:[FileLogger] 用戶 張三 已添加(換DatabaseLogger則輸出對應(yīng)內(nèi)容)
    }
}

改進

  • UserService僅依賴ILogger接口(抽象),與具體實現(xiàn)(FileLogger/DatabaseLogger)解耦。
  • 替換日志實現(xiàn)時,只需修改注入的對象,無需改動UserService代碼,符合 “開閉原則”。

3. 模擬 IoC 容器:自動管理依賴

當(dāng)項目復(fù)雜(依賴層級深,如 A 依賴 B,B 依賴 C),手動注入會非常繁瑣。此時需要 IoC 容器自動處理依賴。下面模擬一個極簡的 IoC 容器:

using System;
using System.Collections.Generic;
using System.Reflection;

// 模擬IoC容器
public class SimpleIocContainer
{
    // 存儲注冊信息:key=接口類型,value=實現(xiàn)類型
    private Dictionary<Type, Type> _registry = new Dictionary<Type, Type>();

    // 注冊:接口 -> 實現(xiàn)
    public void Register<TInterface, TImplementation>() 
        where TImplementation : TInterface
    {
        _registry[typeof(TInterface)] = typeof(TImplementation);
    }

    // 解析:根據(jù)接口類型創(chuàng)建對象,并自動注入依賴
    public T Resolve<T>()
    {
        return (T)Resolve(typeof(T));
    }

    private object Resolve(Type type)
    {
        // 1. 如果是具體類型,直接創(chuàng)建(遞歸終止條件)
        if (!type.IsInterface)
        {
            return CreateInstance(type);
        }

        // 2. 如果是接口,查找注冊的實現(xiàn)類型
        if (!_registry.TryGetValue(type, out Type implementationType))
        {
            throw new Exception($"未注冊接口 {type.Name} 的實現(xiàn)");
        }

        // 3. 創(chuàng)建實現(xiàn)類的實例(并遞歸注入其依賴)
        return CreateInstance(implementationType);
    }

    // 通過反射創(chuàng)建對象,并注入構(gòu)造函數(shù)依賴
    private object CreateInstance(Type type)
    {
        // 獲取類型的構(gòu)造函數(shù)(簡化處理:取第一個構(gòu)造函數(shù))
        ConstructorInfo ctor = type.GetConstructors()[0];
        // 獲取構(gòu)造函數(shù)的參數(shù)(依賴)
        ParameterInfo[] parameters = ctor.GetParameters();

        // 遞歸解析每個參數(shù)的依賴(如UserService的構(gòu)造函數(shù)參數(shù)是ILogger,解析ILogger)
        object[] parameterInstances = new object[parameters.Length];
        for (int i = 0; i < parameters.Length; i++)
        {
            parameterInstances[i] = Resolve(parameters[i].ParameterType);
        }

        // 創(chuàng)建對象(傳入解析好的依賴)
        return ctor.Invoke(parameterInstances);
    }
}

// 使用模擬容器
class Program
{
    static void Main()
    {
        // 1. 創(chuàng)建容器并注冊依賴
        SimpleIocContainer container = new SimpleIocContainer();
        container.Register<ILogger, FileLogger>(); // 注冊ILogger -> FileLogger
        // container.Register<ILogger, DatabaseLogger>(); // 可隨時切換實現(xiàn)

        // 2. 從容器解析UserService(容器自動注入ILogger)
        UserService userService = container.Resolve<UserService>();

        // 3. 調(diào)用方法
        userService.AddUser("李四"); 
        // 輸出:[FileLogger] 用戶 李四 已添加
    }
}

容器工作流程

  1. 注冊:Register<ILogger, FileLogger>() 告訴容器 “ILoggerFileLogger實現(xiàn)”。
  2. 解析:調(diào)用Resolve<UserService>()時,容器通過反射分析UserService的構(gòu)造函數(shù),發(fā)現(xiàn)依賴ILogger
  3. 注入:容器先解析ILogger(根據(jù)注冊找到FileLogger),創(chuàng)建FileLogger實例,再注入到UserService的構(gòu)造函數(shù)中,最終返回UserService實例。

五、總結(jié)

  • 控制反轉(zhuǎn)(IoC):是一種設(shè)計原則,通過將對象的依賴管理控制權(quán)從對象自身轉(zhuǎn)移到外部容器,實現(xiàn) “被動接收依賴”,降低耦合。
  • 依賴注入(DI):是實現(xiàn) IoC 的具體方式,通過構(gòu)造函數(shù)、屬性或方法將依賴傳遞給對象,而非對象自己創(chuàng)建。
  • 實現(xiàn)核心:IoC 容器通過 “注冊 - 解析 - 注入” 流程,利用反射動態(tài)管理對象創(chuàng)建和依賴關(guān)系,簡化開發(fā)并提高代碼靈活性。

在實際開發(fā)中,通常使用成熟的 IoC 容器(如 Autofac、Microsoft.Extensions.DependencyInjection),而非手動實現(xiàn),但理解其原理有助于更好地使用這些工具。

到此這篇關(guān)于C#中控制反轉(zhuǎn)和依賴注入原理及實現(xiàn)的文章就介紹到這了,更多相關(guān)C# 控制反轉(zhuǎn)和依賴注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • VS?Code里使用Debugger?for?Unity插件調(diào)試的方法(2023最新版)

    VS?Code里使用Debugger?for?Unity插件調(diào)試的方法(2023最新版)

    Debugger for Unity是一個非正式支持的,官方推薦的,應(yīng)用最廣的,Visual Studio Code上的Unity調(diào)試插件,這篇文章主要介紹了VS?Code里使用Debugger?for?Unity插件進行調(diào)試(2023最新版),需要的朋友可以參考下
    2023-02-02
  • C#調(diào)用百度API實現(xiàn)活體檢測的方法

    C#調(diào)用百度API實現(xiàn)活體檢測的方法

    這篇文章主要給大家介紹了關(guān)于C#調(diào)用百度API實現(xiàn)活體檢測的方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • C#實現(xiàn)的文件壓縮和解壓縮類

    C#實現(xiàn)的文件壓縮和解壓縮類

    這篇文章主要介紹了C#實現(xiàn)的文件壓縮和解壓縮類,實例分析了C#針對文件壓縮與解壓縮的常用技巧,非常具有實用價值,需要的朋友可以參考下
    2015-03-03
  • C#調(diào)用DeepSeek?API的方法詳解

    C#調(diào)用DeepSeek?API的方法詳解

    DeepSeek(深度求索)?最近可謂火爆的一塌糊涂,具體的介紹這里不再贅述,本文為大家介紹了在C#中調(diào)用DeepSeek?API的方法,希望對大家有所幫助
    2025-02-02
  • c# 繼承快速入門

    c# 繼承快速入門

    這篇文章主要介紹了c# 繼承快速入門的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • VS2019使用快捷鍵將代碼對齊的方法

    VS2019使用快捷鍵將代碼對齊的方法

    這篇文章主要介紹了VS2019使用快捷鍵將代碼對齊的相關(guān)資料,非常不錯對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • C#多線程異步執(zhí)行和跨線程訪問控件Helper

    C#多線程異步執(zhí)行和跨線程訪問控件Helper

    這篇文章介紹了C#多線程異步執(zhí)行和跨線程訪問控件Helper,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • c# 判斷是否為空然后賦值的4種實現(xiàn)方法

    c# 判斷是否為空然后賦值的4種實現(xiàn)方法

    下面小編就為大家分享一篇c# 判斷是否為空然后賦值的4種實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • C#讀寫EXCEL單元格的問題實現(xiàn)

    C#讀寫EXCEL單元格的問題實現(xiàn)

    這篇文章主要介紹了C#讀寫EXCEL單元格的問題實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-04-04
  • C#使用百度Ueditor富文本框?qū)崿F(xiàn)上傳文件

    C#使用百度Ueditor富文本框?qū)崿F(xiàn)上傳文件

    這篇文章主要為大家詳細(xì)介紹了C#如何使用百度Ueditor富文本框?qū)崿F(xiàn)上傳文件(圖片,視頻等),文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-07-07

最新評論

阳城县| 阿拉善左旗| 黄大仙区| 镇巴县| 蕉岭县| 津市市| 余庆县| 宝丰县| 喀喇沁旗| 景宁| 黄骅市| 旬邑县| 洛阳市| 泰州市| 亚东县| 金阳县| 泸定县| 唐海县| 黎川县| 柳河县| 平乐县| 兖州市| 海城市| 固始县| 阿坝县| 云和县| 白水县| 屏东市| 开江县| 康马县| 科尔| 肃北| 红安县| 益阳市| 青岛市| 大田县| 彰武县| 涞水县| 祁门县| 大名县| 会泽县|