線程異步

C# 委托與事件學習筆記(小白入門版)

一、委托(Delegate)基礎

1. 什么是委托?

  • 委托是 C# 中的引用類型,本質是「方法的容器」—— 可像變量一樣存儲、傳遞方法(實現(xiàn) “把方法當參數(shù)用”)。

  • 核心作用:解耦代碼,實現(xiàn)「回調機制」(如方法 A 調用方法 B)、「事件驅動」(如按鈕點擊響應)。

2. 委托的定義與基本使用

(1)定義委托

用 delegate 關鍵字聲明,需明確返回值類型參數(shù)列表(即 “方法簽名”,后續(xù)綁定的方法必須完全匹配)。

語法示例:

// 定義委托:返回值void,參數(shù)為1個string
delegate void MessageDelegate(string content);

(2)綁定方法并調用

委托實例可綁定「靜態(tài)方法」或「實例方法」,調用委托即執(zhí)行綁定的方法。

完整代碼示例:

using System;

// 1. 定義委托(簽名:接收string,返回void)
delegate void GreetDelegate(string name);

class GreetSystem
{
    // 2. 靜態(tài)方法(無需創(chuàng)建對象即可調用)
    static void EnglishGreet(string name)
    {
        Console.WriteLine($"Hello, {name}!");
    }

    // 3. 實例方法(需先創(chuàng)建類對象)
    void ChineseGreet(string name)
    {
        Console.WriteLine($"你好,{name}!");
    }

    static void Main()
    {
        // 綁定靜態(tài)方法
        GreetDelegate greet1 = EnglishGreet;
        greet1("Alice"); // 調用 → 輸出:Hello, Alice!

        // 綁定實例方法(先創(chuàng)建對象)
        GreetSystem system = new GreetSystem();
        GreetDelegate greet2 = system.ChineseGreet;
        greet2("Bob"); // 調用 → 輸出:你好,Bob!
    }
}

二、委托的實例化方式

委托是引用類型,需創(chuàng)建實例才能使用,有兩種常見方式:

1. 顯式實例化(new 關鍵字)

直觀體現(xiàn) “委托是對象”,適合新手理解原理:

// 顯式創(chuàng)建委托實例,綁定目標方法
GreetDelegate greet = new GreetDelegate(EnglishGreet);
greet("Charlie"); // 調用 → 輸出:Hello, Charlie!

2. 隱式實例化(簡化寫法)

編譯器自動創(chuàng)建實例,日常開發(fā)更常用:

// 簡化寫法(等價于顯式實例化)
GreetDelegate greet = EnglishGreet;
greet("David"); // 調用 → 輸出:Hello, David!

三、多播委托(Multicast Delegate)

一個委托實例可綁定多個方法,調用時按 “添加順序” 依次執(zhí)行所有方法(用 += 添加、-= 移除)。

1. 無參數(shù)多播委托

代碼示例:

using System;

// 定義無參數(shù)、無返回值的委托
delegate void NotifyDelegate();

class NotificationSystem
{
    static void SendEmail() => Console.WriteLine("? 發(fā)送郵件通知");
    static void SendSMS() => Console.WriteLine("? 發(fā)送短信通知");
    static void SendPush() => Console.WriteLine("? 發(fā)送推送通知");

    static void Main()
    {
        // 1. 綁定第一個方法
        NotifyDelegate notify = SendEmail;
        
        // 2. 用 += 添加其他方法
        notify += SendSMS;
        notify += SendPush;

        // 3. 調用委托(依次執(zhí)行所有方法)
        Console.WriteLine("觸發(fā)通知:");
        notify(); 
        // 輸出:
        // ? 發(fā)送郵件通知
        // ? 發(fā)送短信通知
        // ? 發(fā)送推送通知

        // 4. 用 -= 移除指定方法
        notify -= SendSMS;
        Console.WriteLine("\n移除短信通知后:");
        notify(); 
        // 輸出:
        // ? 發(fā)送郵件通知
        // ? 發(fā)送推送通知
    }
}

2. 帶參數(shù)多播委托

核心規(guī)則:

  • 所有綁定的方法必須與委托 “參數(shù)列表完全匹配”(類型、數(shù)量、順序一致);

  • 調用時傳入的參數(shù),會共享給所有綁定的方法。

代碼示例:

using System;

// 定義帶1個string參數(shù)的委托
delegate void LogDelegate(string logContent);

class LogSystem
{
    static void LogToConsole(string content) => Console.WriteLine($"[控制臺] {content}");
    static void LogToFile(string content) => Console.WriteLine($"[本地文件] {content}");
    static void LogToServer(string content) => Console.WriteLine($"[遠程服務器] {content}");

    static void Main()
    {
        LogDelegate log = LogToConsole;
        log += LogToFile;
        log += LogToServer;

        // 傳入?yún)?shù),所有方法共享
        log("系統(tǒng)啟動成功(2025-10-21 10:00)");
        // 輸出:
        // [控制臺] 系統(tǒng)啟動成功(2025-10-21 10:00)
        // [本地文件] 系統(tǒng)啟動成功(2025-10-21 10:00)
        // [遠程服務器] 系統(tǒng)啟動成功(2025-10-21 10:00)
    }
}

注意事項:

若委托有返回值,多播委托僅保留最后一個方法的返回值(前序方法的返回值會被忽略),因此多播委托通常用于 void 類型。

四、匿名方法與委托

匿名方法是 “無名稱的臨時方法”,直接在委托中定義,適合 “僅使用一次的簡單邏輯”,減少代碼冗余。

1. 匿名方法綁定委托

代碼示例:

using System;

// 定義委托
delegate void PrintDelegate(string text);

class Program
{
    static void Main()
    {
        // 委托直接綁定匿名方法(用delegate關鍵字定義)
        PrintDelegate print = delegate(string msg)
        {
            Console.WriteLine($"匿名方法輸出:{msg}");
            Console.WriteLine($"當前時間:{DateTime.Now:HH:mm:ss}");
        };

        print("測試匿名方法");
        // 輸出:
        // 匿名方法輸出:測試匿名方法
        // 當前時間:10:30:45(實際時間以運行時為準)
    }
}

2. Lambda 表達式(匿名方法簡化版)

C# 3.0+ 推薦用 Lambda 表達式,語法更簡潔(本質與匿名方法等價):

using System;

class Program
{
    static void Main()
    {
        // 1. 帶參數(shù)的Lambda(匹配PrintDelegate)
        PrintDelegate print1 = msg => 
        {
            Console.WriteLine($"Lambda輸出:{msg}");
        };
        print1("測試帶參數(shù)Lambda"); // 輸出:Lambda輸出:測試帶參數(shù)Lambda

        // 2. 無參數(shù)Lambda(匹配Action委托)
        Action print2 = () => Console.WriteLine("Lambda輸出:無參數(shù)示例");
        print2(); // 輸出:Lambda輸出:無參數(shù)示例

        // 3. 帶返回值的Lambda(匹配Func委托)
        Func<int, int> square = num => num * num;
        Console.WriteLine($"5的平方:{square(5)}"); // 輸出:5的平方:25
    }
}

五、事件(Event)基礎

事件是「委托的安全封裝」,基于委托實現(xiàn) “發(fā)布 - 訂閱” 模式(如 UI 按鈕點擊、消息通知),限制外部對委托的直接修改,更安全。

1. 事件的定義與使用

完整代碼示例:

using System;

// 1. 定義事件對應的委托(標準簽名:sender=事件源,e=事件數(shù)據(jù))
delegate void ButtonClickHandler(object sender, EventArgs e);

// 2. 事件發(fā)布者(如按鈕控件)
class CustomButton
{
    // 定義事件(用event關鍵字,基于委托)
    public event ButtonClickHandler Click;

    // 觸發(fā)事件的方法(通常為public,供外部調用模擬觸發(fā))
    public void OnClick()
    {
        // 先判斷是否有訂閱者(避免空引用異常)
        if (Click != null)
        {
            Click(this, EventArgs.Empty); // 觸發(fā)事件
        }
        // 簡化寫法(C# 6.0+ 空合并運算符)
        // Click?.Invoke(this, EventArgs.Empty);
    }
}

// 3. 事件訂閱者(如業(yè)務邏輯類)
class Program
{
    static void Main()
    {
        // 創(chuàng)建按鈕實例(發(fā)布者)
        CustomButton btn = new CustomButton();

        // 訂閱事件(用+=綁定處理方法)
        btn.Click += Btn_Click1;
        btn.Click += Btn_Click2;

        // 模擬按鈕點擊(觸發(fā)事件)
        Console.WriteLine("點擊按鈕:");
        btn.OnClick();
    }

    // 事件處理方法1
    static void Btn_Click1(object sender, EventArgs e)
    {
        Console.WriteLine("處理方法1:按鈕被點擊,執(zhí)行邏輯A");
    }

    // 事件處理方法2
    static void Btn_Click2(object sender, EventArgs e)
    {
        Console.WriteLine("處理方法2:按鈕被點擊,執(zhí)行邏輯B");
    }
}
// 輸出:
// 點擊按鈕:
// 處理方法1:按鈕被點擊,執(zhí)行邏輯A
// 處理方法2:按鈕被點擊,執(zhí)行邏輯B

2. 事件的核心特性

  • 安全限制:外部只能用 +=(訂閱)和 -=(取消訂閱),不能直接賦值(如 btn.Click = null)或調用(如 btn.Click()),避免委托被意外修改。

  • 發(fā)布 - 訂閱分離:發(fā)布者(如按鈕)負責觸發(fā)事件,訂閱者(如業(yè)務邏輯)負責處理事件,解耦代碼。

六、學習路線總結

  1. 基礎認知:委托是 “方法的引用”→ 掌握定義、綁定、調用;

  2. 進階使用:多播委托用 +=/-= 管理多個方法 → 理解參數(shù)共享和返回值特性;

  3. 簡化寫法:匿名方法 / Lambda 減少代碼冗余 → 熟練使用 Action/Func 預定義委托;

  4. 安全封裝:事件基于委托實現(xiàn)發(fā)布 - 訂閱 → 掌握事件的定義、訂閱和觸發(fā)。

按此順序練習,結合代碼示例調試,可逐步掌握委托與事件的核心用法!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容