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

C# 委派、事件與 Lambda 深度解析:從函數指標到函數式思維

     編輯:關於C語言

前言

委派 是 C# 實現「函數作為一等公民」的基石,事件 建立在委派之上,Lambda 表達式則是匿名方法的語法糖,三者環環相扣。本文將從委派本質、多播機制、事件模式、協變逆變、匿名方法到 Lambda 及運算式樹,完整串聯核心知識脈絡。

一、委派本質:型別安全的函數指標

delegate int Transformer(int x); // 宣告委派型別

static int Square(int x) => x * x;
static int Cube(int x) => x * x * x;

Transformer t = Square;           // 指派靜態方法
Transformer t2 = new Transformer(Cube); // 等價寫法
int result = t(5);                // 呼叫委派 (25)
  • 委派是 **Reference Type**,繼承自 MulticastDelegate。
  • 封裝 **方法指標 + 目標物件參考** (實例方法需物件,靜態方法為 null)。
  • 支援 **協變/逆變**:回傳型別可為衍生類 (out),參數型別可為基類 (in)。

二、多播委派:鏈式呼叫

Transformer multi = Square;
multi += Cube;                    // 串聯
multi += x => -x;                 // 加入 Lambda

foreach (Transformer d in multi.GetInvocationList())
    Console.WriteLine(d(3));      // 9, 27, -3

int last = multi(3);              // 只取最後一個回傳值 (-3)

每個委派實例維護一個調用清單,+=/-= 建立新委派實例 (不可變)。

三、事件模式:發布-訂閱的標準化

// 1. 宣告事件 (慣用 EventHandler 模式)
public class Timer
{
    public event EventHandler Elapsed;

    protected virtual void OnElapsed(ElapsedEventArgs e)
    {
        Elapsed?.Invoke(this, e); // Null 條件運算子,執行緒安全
    }
}

// 2. 訂閱
var timer = new Timer();
timer.Elapsed += (sender, e) => Console.WriteLine($"Tick at {e.SignalTime}");

// 3. 自訂 EventArgs 攜帶資料
public class ElapsedEventArgs : EventArgs
{
    public DateTime SignalTime { get; }
    public ElapsedEventArgs(DateTime t) => SignalTime = t;
}

關鍵規則:事件只能在宣告類別內部 Invoke,外部僅能 +=/-=,封裝了多播委派的直接呼叫權限。

四、演進史:委派 → 匿名方法 → Lambda → 運算式樹

版本語法範例特性
C# 1.0具名方法t = new Transformer(Square);需額外方法
C# 2.0匿名方法t = delegate(int x) { return x * x; };內嵌程式碼區塊,可捕獲外部變數
C# 3.0Lambda 運算式t = x => x * x;型別推斷、單行隱含 return、支援運算式樹

五、Lambda 兩種形態

  • 運算式 Lambda:x => x * x — 單一運算式,可轉為 Expression<Func<int,int>> 建構運算式樹 (LINQ to SQL 核心)。
  • 陳述式 Lambda:x => { Console.WriteLine(x); return x * x; } — 多行程式碼,僅能編譯為委派/匿名方法,不可 轉為運算式樹。

六、閉包與變數捕獲陷阱

var funcs = new List>();
for (int i = 0; i < 3; i++)
    funcs.Add(() => i); // 捕獲迴圈變數 i

foreach (var f in funcs) Console.WriteLine(f()); // 全印 3!

// 修正:區域副本
for (int i = 0; i < 3; i++)
{
    int captured = i;
    funcs.Add(() => captured);
}
// 印出 0, 1, 2

七、標準委派:Func / Action / Predicate

  • Func<T1..Tn, TResult>:有回傳值 (最多 16 參數)。
  • Action<T1..Tn>:無回傳值。
  • Predicate<T>:Func<T, bool> 別名,常用於 List.FindAll。

善用標準委派減少自訂 delegate 宣告,提升程式碼互通性。

八、總結

委派提供「方法參考」的型別安全封裝,事件在其上建立發布-訂閱契約,Lambda 讓內嵌函數寫法極致簡潔並開啟運算式樹大門。掌握三者關係與演進脈絡,是寫出優雅、可擴充、函數式風格 C# 程式碼的關鍵。

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