Learning hard C#學習筆記——讀書筆記 06

来源:https://www.cnblogs.com/trueasureyuki/archive/2023/07/19/17563994.html
-Advertisement-
Play Games

本文介紹了 C# 中委托的定義、使用、為什麼引入委托以及委托的本質。同時,還介紹了委托鏈的使用,即將多個委托鏈接在一起,提高程式的可擴展性。 ...



之前的大部分內容,其實都是面向對象語言的共性,而這次的委托是 C# 特有的內容


1.委托的定義


C# 中的委托可以理解為函數的包裝,它使得 C# 中的函數可以作為參數來傳遞(類似於JavaScript中的高級函數),作用上相當於C++中的函數指針,C++用函數指針獲取函數的入口地址,然後通過這個指針實現對函數的操作

委托的定義和方法的定義類似,只是在前面多了一個delegate關鍵字


public delegate void MyDelegate(int para1,string para2);

委托包裝方法的條件

  1. 方法的簽名必須和委托一致,方法簽名包括參數的個數、類型、順序
  2. 方法的返回類型要和委托一致(方法的返回類型不屬於方法簽名的一部分)

簡單來說,如圖所示:


簡單來說,就是我們將MyMethod()方法委托給了MyDelegate()去執行了


2.委托的使用


class Program {

    // 1.使用delegate定義委托使用
    delegate void MyDelegate(int a, int b);

    public static void Main(string[] args) {

        // 2.聲明委托變數d
        MyDelegate d;
        // 3.實例化委托變數d
        d = new MyDelegate(new Program().add);

        // 4.委托作為參數進行傳遞
        MyMethod(d);
        Console.Read();
    }

    public void add(int a, int b) {
        int c = a + b;
        Console.WriteLine("最後的結果為:{0}",c);
    }

    private static void MyMethod(MyDelegate mydelegate) {
        // 5.在方法中調用委托
        mydelegate(1, 2);
    }
}


委托使用的註意點

  1. 委托實例化傳遞的參數,必須和委托定義相同,即方法的返回類型和參數個數、參數類型都碧血和委托相同,並且,傳遞的是方法名(不帶括弧)
  2. 委托的調用,與方法調用類似,傳遞的實際參數個數必須與委托定義一致
  3. 委托是方法包裝類型,所以委托的調用實際上是對包裝的方法的調用

3.為什麼引入委托


我們先看一個沒有委托的寫法

我們可以發現,沒有委托,如果我們打招呼的方式多了起來,則Greet中的switch case語句要一直寫下去,根據“開閉原則”(對擴展開發,對修改關閉),我們是不建議這樣去寫的


class Program {

    public static void Main(string[] args) {
        Program p = new Program();
        p.Greet("李廣", "zh-cn");
    }


    public void Greet(string name,string language) {
        switch (language) {
            case "zh-cn":
                ChineseGreeting(name);
                break;
            case "en-us":
                EnlishGreeting(name);
                break;
            default:
                EnlishGreeting(name);
                break;
        }
    }

    // 1.中國人打招呼的方式
    public void ChineseGreeting(string name) {
        Console.WriteLine("你好"+name);
    }

    public void EnlishGreeting(string name) {
        Console.WriteLine("Hello"+name);
    }
}

而如果我們使用了委托,我們可以不破壞原有的代碼內容,只需要在後面繼續添加新的打招呼方法就可以,這樣提高了程式的可擴展性


class Program {

    public delegate void GreetDelegate(string name);

    public static void Main(string[] args) {
        Program p = new Program();
        p.Greet("李廣", p.EnlishGreeting);
        p.Greet("李廣", p.ChineseGreeting);
    }


    public void Greet(string name, GreetDelegate callback) {
        callback(name);
    }

    // 1.中國人打招呼的方式
    public void ChineseGreeting(string name) {
        Console.WriteLine("你好"+name);
    }

    public void EnlishGreeting(string name) {
        Console.WriteLine("Hello"+name);
    }
}

4.委托的本質


class Program {
    public delegate void DelegateTest(int parm);

    static void Main(string[] args) {
        Console.WriteLine("調用");
    }
}


用以上的代碼來反編譯一下,我們發現DelegateTest委托類型使用了.class關鍵字進行標識,所以 C# 編譯器會把我們定義的委托類型,編譯成如下的類類型


IAsyncResult和EndInvoke 這兩個方法是非同步方法



我們可以對Invoke進行顯式調用,最後,我們可以清楚的看到,委托是類類型


最後我們發現,其本質也就是調用了Invoke方法來執行對應的方法



總結:

委托的本質,其實就是一個類,這個類中一共有四個方法

  1. 構造方法
  2. Invoke()調用函數參數的方法
  3. 一個非同步獲取方法返回值的方法
  4. 一個非同步執行參數方法的方法


5.委托鏈


前面都是委托封裝一個方法的情況,即一個委托只為一個方法服務,但是也有一個委托為多個方法服務的情況,C# 中把封裝多個方法的委托稱為委托鏈或多路廣播委托



5.1 委托鏈的使用

委托鏈其實就是委托類型,只是委托鏈將多個委托鏈接在一起了而已

向委托鏈中添加委托是使用 + ,那麼移除委托就是使用 - ,委托鏈中移除委托後,仍然可以將委托移動到其它委托鏈中


class Program
{

    public delegate void DelegateTest();

    static void Main(string[] args) {
        // 1.委托1
        DelegateTest delegateMethod1 = new DelegateTest(Program.method1);
        // 2.委托2
        DelegateTest delegateMethod2 = new DelegateTest(new Program().method2);

        // 3.定義委托鏈
        DelegateTest delegateChain = null;
        // 4.向委托鏈中添加委托
        delegateChain += delegateMethod1;
        delegateChain += delegateMethod2;

        delegateChain();
        Console.Read();
    }


    private static void method1() {
        Console.WriteLine("這是靜態方法");
    }
  
    private  void method2() { Console.WriteLine("這是實例方法"); }
}



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 1.模塊 ``` import 模塊名 ``` ## 1.1 模塊就是程式 任何python程式都可以作為模塊導入,並標明程式(模塊)的位置 ``` import sys sys.path.append('路徑') ``` ``` import hello // 在同一文件夾下 ``` 會在該文 ...
  • [toc] # 引入 - Microsoft.EntityFrameworkCore - Microsoft.EntityFrameworkCore.Design - Microsoft.EntityFrameworkCore.SqlServer - Microsoft.EntityFramewor ...
  • # 一、日誌記錄 日誌記錄是什麼?簡單而言,就是通過一些方式記錄應用程式運行中的某一時刻的狀態,保留應用程式當時的信息。這對於我們進行應用程式的分析、審計以及維護有很大的作用。 作為程式員,我們恐怕誰也不敢保證我們開發的軟體應用一定不存在BUG,一定不會出現故障,而當故障出現的時候,日誌就是我們排查 ...
  • # 基於Avalonia 11.0.0+ReactiveUI 的跨平臺項目開發2-功能開發 ![image-20230718225201652](https://www.raokun.top/upload/2023/07/image-20230718225201652.png) **項目簡介**:目 ...
  • 在使用DevExpress的GridView的時候,我們為了方便,往往使用一些擴展函數,動態創建GridView列的編輯控制項對象,然後我們可以靈活的對內容進行編輯或者使用一些彈出的對話框窗體進行處理內容的錄入,本篇隨筆就是介紹這一主題:在DevExpress的GridView的列中,動態創建列的時候... ...
  • ## 簡介 ##### IoC Ioc控制反轉,是一種設計模式和原則,旨在解耦組件之間的依賴關係,並將對象的創建和管理委托外部容器。是面向編程中一種重要的概念,用於提高代碼的可維護性. 核心思想:通過將控制權從高層轉移到底層模塊,實現對依賴關係的控制反轉,傳統上,一個對象通常負責自己的依賴項創建和管 ...
  • 本文介紹了值類型和引用類型在編程中的區別。值類型包括簡單類型、枚舉類型和結構體類型,通常被分配線上程的堆棧上,變數保存的是實例數據本身。引用類型實例則被分配在托管堆上,變數保存的是實例數據的記憶體地址。值類型由操作系統負責管理,而引用類型則由垃圾回收機制(GC)負責管理。本文還通過示例代碼展示了值類型... ...
  • ## 一:背景 ### 1. 講故事 這篇文章源自於分析一些疑難dump的思考而產生的靈感,在dump分析中經常要尋找的一個答案就是如何找到死亡線程的生前都做了一些什麼?參考如下輸出: ``` C# 0:001> !t ThreadCount: 22 UnstartedThread: 0 Backg ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...