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

C# 3.0 Lambda 表達式完整教學:從委派、匿名方法到 Lambda 的演進與 LINQ 核心應用

     編輯:關於C#

演進脈絡:委派 → 匿名方法 → Lambda 表達式

1. 委派 與 命名方法 (C# 1.0)


// 定義委派型別
public delegate bool IntFilter(int i);

public class Common
{
    public static int[] FilterArray(int[] source, IntFilter filter)
    {
        var list = new List();
        foreach (int i in source)
            if (filter(i)) list.Add(i);
        return list.ToArray();
    }
}

// 算法實作為獨立命名方法
public class Algorithms
{
    public static bool IsOdd(int i) => (i & 1) == 1;
    public static bool IsEven(int i) => (i & 1) == 0;
    public static bool GreaterThan5(int i) => i > 5;
}

// 呼叫端
int[] numbers = { 1,2,3,4,5,6,7,8,9,10 };
var odds = Common.FilterArray(numbers, Algorithms.IsOdd); // 傳遞方法群組

2. 匿名方法 (C# 2.0)


// 內聯定義算法,無需獨立方法
var odds = Common.FilterArray(numbers, delegate(int i) { return (i & 1) == 1; });

// 捕獲外部變數 (閉包)
int threshold = 5;
var greater = Common.FilterArray(numbers, delegate(int i) { return i > threshold; });

3. Lambda 表達式 (C# 3.0) - 現代標準


// 完整語法:(參數) => { 陳述式; return 結果; }
var odds = Common.FilterArray(numbers, (int i) => { return (i & 1) == 1; });

// 單一運算式簡寫:隱含 return、類型推斷
var odds = Common.FilterArray(numbers, i => (i & 1) == 1);

// 多參數需括號
var compare = (int x, int y) => x == y;

// 無參數
var getTime = () => DateTime.Now;

// 陳述式主體 (多行)
var complex = (int x, int y) => 
{
    if (x > y) return x;
    return y;
};

Lambda 核心語法規則

形式範例說明
單參數隱含類型x => x * 2最常用
單參數顯式類型(int x) => x * 2需明確類型時
多參數(x, y) => x + y括號必要
無參數() => "Hello"空括號必要
陳述式主體x => { Console.WriteLine(x); return x*2; }大括號 + 明確 return
運算式主體x => x * 2隱含 return,無大括號
異步 Lambdaasync x => await Fetch(x)C# 5.0+

閉包與變數捕獲機制


public void DemoCapture()
{
    int factor = 10;
    Func multiply = x => x * factor; // 捕獲 factor

    factor = 20; // 修改外部變數
    Console.WriteLine(multiply(5)); // 輸出 100 (捕獲的是變數,非值!)

    // 迴圈陷阱
    var funcs = new List>();
    for (int i = 0; i < 3; i++)
    {
        int captured = i; // 關鍵:建立區域副本
        funcs.Add(() => captured);
    }
    // 輸出 0, 1, 2 (正確)
    // 若直接捕獲 i,輸出 3, 3, 3 (錯誤)
}

Lambda 與 LINQ 黃金搭檔

Lambda 表達式是 LINQ 標準查詢運算子的核心參數型別 (Func<T, bool>, Func<T, TResult>)。


var numbers = Enumerable.Range(1, 100);

var result = numbers
    .Where(n => n % 2 == 0)        // 篩選偶數
    .Select(n => n * n)            // 投影平方
    .Take(10)                      // 取前 10
    .OrderByDescending(n => n)     // 降序
    .ToList();

// 方法語法 vs 查詢語法
var q = from n in numbers
        where n % 2 == 0
        select n * n; // 編譯器轉換為 Where/Select Lambda

Func/Action/Predicate 委派與 Lambda

委派型別參數回傳Lambda 範例
Action無void() => Console.WriteLine("Hi")
Action<T>1voidx => Console.WriteLine(x)
Func<TResult>無TResult() => 42
Func<T, TResult>1TResultx => x.ToString()
Func<T1, T2, TResult>2TResult(x, y) => x + y
Predicate<T>1boolx => x > 0

表達式樹 進階應用


using System.Linq.Expressions;

// Lambda 編譯為委派 (執行碼)
Func func = x => x * 2;
int result = func(5); // 10

// Lambda 編譯為表達式樹 (資料結構,可分析/轉換)
Expression> expr = x => x * 2;
// 應用:Entity Framework 將表達式樹翻譯為 SQL
// 應用:動態建構查詢、序列化規則引擎

// 手動建構表達式樹
var param = Expression.Parameter(typeof(int), "x");
var body = Expression.Multiply(param, Expression.Constant(2));
var lambda = Expression.Lambda>(body, param);
var compiled = lambda.Compile(); // 回到委派

最佳實踐與避坑指南

  1. 優先用 Lambda:單次使用、簡短邏輯、LINQ 查詢。
  2. 命名方法:複雜邏輯、需重用、需單元測試、遞迴呼叫。
  3. 避免過長 Lambda:超過 3 行建議提取為方法,保持可讀性。
  4. 迴圈捕獲陷阱:`for/foreach` 中捕獲迴圈變數務必建立區域副本。
  5. 異步 Lambda:`async` Lambda 回傳 `Task`,勿忘 `await`。
  6. 序列化限制:Lambda 無法直接序列化,需表達式樹或自定義格式。

總結

Lambda 表達式是 C# 函數式程式設計的基石,極大簡化了委派使用語法,配合 LINQ 實現聲明式資料處理。理解其閉包捕獲語意、類型推斷規則與表達式樹雙重身分,是掌握現代 C# 開發的關鍵。

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