首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 委派完整入門指南:宣告、實例化、多播、匿名方法與 Lambda 表達式

     編輯:關於C語言

前言

委派 是 C# 實現「方法作為參數傳遞」、「回呼」、「事件處理」的核心機制。它是型別安全的物件導向函數指標。本文從基礎語法、實例化方式、多播委派、匿名方法到 Lambda 表達式,系統建立完整知識圖譜。

一、委派基礎

宣告語法

// 宣告一個委派型別:接受兩個 int,回傳 int
public delegate int PerformCalculation(int x, int y);

// 宣告無回傳值、接受字串的委派
public delegate void Del(string message);

核心特性

  • 型別安全:簽名(參數型別、順序、回傳型別)必須完全匹配。
  • 物件導向:委派是衍生自 System.Delegate 的密封類別實例。
  • 封裝靜態或實例方法:實例方法委派同時持有目標物件引用與方法指標。
  • 支援多播:可串聯多個方法,依序呼叫。
  • 共變性/逆變性:方法參數可為委派參數的基類(逆變性),回傳型別可為委派回傳型別的衍生類(共變性)。

二、委派實例化與呼叫

1. 命名方法實例化

public static void DelegateMethod(string message) {
    Console.WriteLine(message);
}

// 實例化
Del handler = DelegateMethod; // 方法群組轉換

// 呼叫
handler("Hello World"); // 輸出: Hello World

2. 作為參數傳遞(回呼模式)

public void MethodWithCallback(int p1, int p2, Del callback) {
    callback($"The number is: {p1 + p2}");
}

// 使用
MethodWithCallback(1, 2, handler); // 輸出: The number is: 3

3. 封裝實例方法 vs 靜態方法

public class MethodClass {
    public void Method1(string msg) { Console.WriteLine($"Instance: {msg}"); }
    public void Method2(string msg) { Console.WriteLine($"Instance2: {msg}"); }
}

var obj = new MethodClass();
Del d1 = obj.Method1;  // 封裝實例方法:持有 obj 引用
Del d2 = obj.Method2;
Del d3 = DelegateMethod; // 封裝靜態方法:僅持有方法指標

三、多播委派

委派可透過 +/+= 組合,-/-= 移除。

組合與呼叫

Del all = d1 + d2;     // 組合
all += d3;             // 追加

all("Test");           // 依序呼叫 Method1, Method2, DelegateMethod

關鍵行為

  • 呼叫順序:依加入順序依序執行。
  • 參數傳遞:所有方法共享相同參數;若為 ref 參數,修改會傳遞給後續方法。
  • 例外處理:若某方法拋出未捕獲例外,後續方法不再執行,例外向上傳播。
  • 回傳值:僅保留最後一個方法的回傳值(輸出參數同理)。

移除方法

all -= d1;                    // 移除 d1
Del single = all - d2;        // 建立新委派,排除 d2

檢查調用清單

int count = all.GetInvocationList().Length; // 取得方法數量

四、委派比較

  • 相同委派型別:可用 ==/!= 比較,比較調用清單是否相同。
  • 不同委派型別:編譯期錯誤。
  • 轉為 System.Delegate:編譯通過,運行時若實際型別不同則回傳 false。

五、匿名方法

C# 2.0 引入,允許內嵌代碼區塊作為委派主體。

語法

Del anon = delegate(string msg) {
    Console.WriteLine($"Anonymous: {msg}");
};

anon("Hi"); // 輸出: Anonymous: Hi

特性

  • 可存取外層區域變數(捕獲變數),形成閉包。
  • 參數列表可省略(若不使用參數):delegate { ... }。
  • 不可包含 goto、break、continue 跳出區塊。

六、Lambda 表達式

C# 3.0 引入,更簡潔的匿名函數語法,編譯為委派或運算式樹。

語法形式

(參數列表) => 運算式或語句區塊

範例

// 運算式 Lambda(隱含回傳)
Func add = (x, y) => x + y;

// 語句 Lambda
Action log = msg => {
    var time = DateTime.Now;
    Console.WriteLine($"{time}: {msg}");
};

// 無參數
Action sayHi = () => Console.WriteLine("Hi");

// 隱含型別參數(編譯器推斷)
var multiply = (int x, int y) => x * y;

Lambda vs 匿名方法

特性匿名方法Lambda 表達式
語法簡潔度較冗長極簡潔
型別推斷需明確宣告參數型別支援隱含型別
轉換為運算式樹不支援支援 (Expression<TDelegate>)
參數可省略可 delegate { }無參數需 () =>

七、實戰範例:排序回呼

var list = new List { 5, 2, 9, 1, 3 };

// 使用 Lambda 定義比較邏輯
list.Sort((a, b) => b.CompareTo(a)); // 降序

// 等價匿名方法
list.Sort(delegate(int a, int b) { return b.CompareTo(a); });

// 等價命名方法
list.Sort(CompareDesc);

static int CompareDesc(int a, int b) => b.CompareTo(a);

八、事件與委派的關係

  • event 關鍵字在委派型別上增加封裝:僅允許 +=/-=,禁止外部直接呼叫或指派 =。
  • 事件發布者決定委派型別;訂閱者提供處理方法並建立委派註冊。
  • 標準事件模式:EventHandler / EventHandler<TEventArgs>。

九、最佳實踐總結

  1. 優先使用 Func<...>、Action<...>:內建泛型委派,減少自訂委派宣告。
  2. 事件嚴格使用 event 關鍵字,防止外部誤呼叫。
  3. Lambda 表達式優於匿名方法:更簡潔、支援運算式樹、型別推斷更強。
  4. 避免在多播委派使用 out 參數:無法確定哪個方法被呼叫。
  5. 捕獲變數注意生命週期:閉包會延長被捕獲變數壽命,可能造成記憶體洩漏。
  6. 大量頻繁委派呼叫考慮 delegate* 函數指標(.NET Core 3.0+ / C# 9.0+)以提升效能。

十、結語

委派是 C# 函數式程式設計、事件驅動架構、非同步模式的基石。從 delegate 關鍵字到 Lambda 表達式,語法演進始終圍繞「將行為作為資料傳遞」這一核心。熟練掌握委派的宣告、實例化、多播、閉包與型別推斷,是邁向 C# 專家的關鍵一步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved