一. 基本 Lambda 语法

1.1核心概念

Lambda表达式是一种匿名函数,用于创建委托或表达式树对象。其核心运算符 =>读作“goes to”。

1.2语法结构

左侧是输入参数列表,可以是 ()x(x, y)

右侧是表达式体(单行,隐含return)或语句块{}(多行,需显式return)。

1.3详细说明与示例

a.无参数Lambda

语法() => expression/statement

示例Action sayHello = () => Console.WriteLine(“Hello, Lambda!”);

特性解析()表示无参数,右侧表达式体执行一个操作,赋值给Action委托。

b.单参数Lambda(可推断类型)

语法param => expression

示例Func square = x => x * x;

特性解析:参数x的类型由委托Func推断为int。右侧表达式x * x的结果自动返回。

c.多参数Lambda

语法(param1, param2, ...) => expression

示例Func add = (a, b) => a + b;

特性解析:多个参数必须用括号()包围。

d.显式指定参数类型

语法(Type1 param1, Type2 param2) => expression

示例Func repeat = (string s, int n) => string.Concat(Enumerable.Repeat(s, n));

特性解析:当编译器无法推断类型时,需显式声明参数类型。

e.语句Lambda(多行)

语法param => { statement1; statement2; return value; }

示例

Action printTable = n =>
{
    Console.WriteLine($“{n}的乘法表:”);
    for (int i = 1; i <= 10; i++) Console.WriteLine($“  {n} × {i} = {n * i}”);
};

特性解析:当逻辑复杂时,使用花括号{}构成语句块。无返回值时用Action,有返回值时用Func并在块内return

f.带复杂逻辑的语句Lambda

示例

Func fizzBuzz = n =>
{
    if (n % 15 == 0) return “FizzBuzz”;
    if (n % 3 == 0) return “Fizz”;
    if (n % 5 == 0) return “Buzz”;
    return n.ToString();
};

特性解析:展示了在Lambda语句块中使用条件判断等复杂逻辑。

1.4例程

#region 1. 基本 Lambda 语法

/// <summary>
/// 演示 Lambda 表达式的基本语法结构
/// Lambda 运算符:=> 读作 "goes to" 或 "becomes"
/// 左侧:输入参数列表(可为空、单个或多个参数)
/// 右侧:表达式或语句块(返回值或执行操作)
/// </summary>
static void DemonstrateBasicSyntax()
{
    Console.WriteLine("=== 1. 基本 Lambda 语法 ===");
    Console.WriteLine();

    // 1.1 无参数 Lambda
    // 语法:() => expression/statement
    // () : 空参数列表,表示不接受任何参数
    // => : Lambda 运算符,分隔参数和函数体
    // Console.WriteLine(...) : 函数体,执行的操作
    Action sayHello = () => Console.WriteLine("Hello, Lambda!");
    // Action: 无参数、无返回值的委托类型
    // sayHello: 委托变量,存储 Lambda 表达式
    sayHello();  // 调用委托,执行 Lambda

    // 1.2 单参数 Lambda(参数类型可推断,可省略括号)
    // 语法:param => expression
    // x : 输入参数,类型由委托自动推断为 int
    // x * x : 表达式体,计算结果自动返回
    Func<int, int> square = x => x * x;
    // Func<int, int>: 泛型委托
    // 第一个 int: 输入参数类型
    // 第二个 int: 返回值类型
    Console.WriteLine($"5 的平方:{square(5)}");  // 传入 5,返回 25

    // 1.3 多参数 Lambda
    // 语法:(param1, param2, ...) => expression
    // (a, b) : 多个参数必须用括号包围
    // a + b : 表达式体,返回两数之和
    Func<int, int, int> add = (a, b) => a + b;
    // Func<int, int, int>: 
    // 前两个 int: 输入参数类型
    // 最后一个 int: 返回值类型
    Console.WriteLine($"3 + 7 = {add(3, 7)}");  // 传入 3 和 7,返回 10

    // 1.4 显式指定参数类型
    // 当编译器无法推断类型时,需要显式声明
    // (string s, int n) : 显式指定每个参数的类型
    Func<string, int, string> repeat = (string s, int n) => string.Concat(Enumerable.Repeat(s, n));
    // string.Concat: 连接字符串
    // Enumerable.Repeat(s, n): 生成包含 n 个 s 的序列
    Console.WriteLine($"重复字符串:{repeat("C#", 3)}");  // 输出:C#C#C#

    // 1.5 语句 Lambda(多行)
    // 当需要多条语句时,使用代码块 { }
    // n : 输入参数
    // { ... } : 语句块,可包含多条语句
    Action<int> printMultiplicationTable = n =>
    {
        Console.WriteLine($"{n}的乘法表:");
        for (int i = 1; i <= 10; i++)
        {
            Console.WriteLine($"  {n} × {i} = {n * i}");
        }
    };
    // Action<int>: 接受一个 int 参数,无返回值
    printMultiplicationTable(7);  // 打印 7 的乘法表

    // 1.6 带复杂逻辑的 Lambda
    // 使用 if-else 条件判断的语句 Lambda
    Func<int, string> fizzBuzz = n =>
    {
        if (n % 15 == 0) return "FizzBuzz";  // 能被 15 整除
        if (n % 3 == 0) return "Fizz";       // 能被 3 整除
        if (n % 5 == 0) return "Buzz";       // 能被 5 整除
        return n.ToString();                 // 其他情况返回数字本身
    };
    // Func<int, string>: 接受 int,返回 string

    Console.WriteLine("FizzBuzz 示例:");
    for (int i = 1; i <= 5; i++)
    {
        Console.WriteLine($"  {i}: {fizzBuzz(i)}");
    }
}
#endregion

1.5输出

=== 1. 基本 Lambda 语法 ===

Hello, Lambda!
5 的平方:25
3 + 7 = 10
重复字符串:C#C#C#
7的乘法表:
  7 × 1 = 7
  7 × 2 = 14
  7 × 3 = 21
  7 × 4 = 28
  7 × 5 = 35
  7 × 6 = 42
  7 × 7 = 49
  7 × 8 = 56
  7 × 9 = 63
  7 × 10 = 70
FizzBuzz 示例:
  1: 1
  2: 2
  3: Fizz
  4: 4
  5: Buzz

二. 委托与 Lambda

2.1核心概念

委托的核心作用实现方法的间接调用。将一个方法“赋值”给一个委托变量,然后通过调用这个变量来调用它背后所引用的方法。这使得方法可以像参数一样被传递,是实现回调函数、事件机制以及LINQ的基石。

委托是Lambda的“容器”或“目标类型”,而Lambda是创建委托实例最简洁的语法形式。​ 可以将Lambda看作是为实现委托而“生”的。

详细解释

  1. Lambda 表达式本质上是一个匿名方法。它没有自己的名字,但有一个方法体。

  2. 一个匿名方法(Lambda)必须被赋值给一个具有匹配签名的委托类型变量,才能被存储和调用。委托类型为Lambda提供了所需的“方法签名”信息。

  3. Lambda 极大地简化了委托实例的创建过程。在C#早期,创建委托实例需要先定义一个具名方法,然后将其“分配给”委托。Lambda允许在使用的地方即时定义方法逻辑。

.NET提供了Action(无返回值)、Func(有返回值)、Predicate(返回bool)等内置委托。

2.2语法结构

Lambda的书写语法同上,重点是理解如何赋值给各种委托类型。

2.3详细说明与示例

a.使用内置委托

Action示例Action logMessage = message => Console.WriteLine($“[LOG] {message}”);

Func示例Func calculateHypotenuse = (a, b) => Math.Sqrt(a * a + b * b);

Predicate示例Predicate isPrime = n => { … return true/false; };

特性解析:Lambda表达式无缝兼容这些内置委托,简化了代码。

b.自定义委托

示例BinaryOperation multiply = (x, y) => x * y;BinaryOperation是自定义的delegate int BinaryOperation(int a, int b);

特性解析:Lambda同样可以实现自定义委托类型。

c.多播委托与委托链

示例

multiAction += () => Console.WriteLine(“动作 2”);

Action actionToRemove = () => Console.WriteLine("动作 2");multiAction -= actionToRemove;

特性解析:多个Lambda(或方法)可以通过+=运算符组合成一个委托链,调用时按顺序执行。移除委托需要相同的引用才能移除。委托的 +=-=操作,比较的是委托实例的引用(内存地址)是否相同,而不是比较它们背后方法(或Lambda)的代码是否相同。虽然两个Lambda表达式 () => Console.WriteLine("动作 2")代码文本上完全一样,但C#编译器会将每一个独立的Lambda表达式编译成一个全新的、匿名的方法。因此,它们对应的是两个不同的方法实例,在内存中是两个不同的引用

d.委托作为参数(高阶函数)

示例ProcessNumbers(data, filter: n => n % 2 == 0, processor: n => Console.WriteLine($“偶数:{n}”));

特性解析:Lambda可以作为参数传递给另一个方法,使该方法的行为由调用方决定,极大地增强了灵活性。

2.4例程

#region 2. 委托与 Lambda

/// <summary>
/// 自定义委托类型 - 二元数学运算
/// delegate: 关键字,定义委托类型
/// int: 返回值类型
/// BinaryOperation: 委托名称
/// (int a, int b): 参数列表
/// </summary>
/// <param name="a">第一个操作数</param>
/// <param name="b">第二个操作数</param>
/// <returns>运算结果</returns>
delegate int BinaryOperation(int a, int b);

/// <summary>
/// 演示委托与 Lambda 的结合使用
/// 委托是 Lambda 的载体,Lambda 是委托的实现
/// </summary>
static void DemonstrateDelegatesAndLambda()
{
    Console.WriteLine();
    Console.WriteLine("=== 2. 委托与 Lambda ===");
    Console.WriteLine();

    // 2.1 使用内置委托类型

    // Action<T> - 无返回值,有参数
    // message: Lambda 参数,类型为 string
    // Console.WriteLine(...): 执行的操作,无返回值
    Action<string> logMessage = message => Console.WriteLine($"[LOG] {DateTime.Now:HH:mm:ss}: {message}");
    // Action<string>: 
    // string: 唯一的参数类型
    // 无返回值(void)
    logMessage("程序启动");
    logMessage("Lambda 演示开始");

    // Func<T1, T2, TResult> - 有返回值
    // (a, b): 两个 double 类型参数
    // Math.Sqrt(a * a + b * b): 计算斜边长度并返回
    Func<double, double, double> calculateHypotenuse = (a, b) => Math.Sqrt(a * a + b * b);
    // Func<double, double, double>:
    // 第一个 double: 参数 a 的类型
    // 第二个 double: 参数 b 的类型
    // 第三个 double: 返回值类型
    double hypotenuse = calculateHypotenuse(3, 4);
    Console.WriteLine($"直角三角形斜边 (3, 4): {hypotenuse}");  // 输出:5

    // Predicate<T> - 返回 bool 的委托,用于判断
    // n: 输入参数,类型为 int
    // { ... }: 语句块,返回 true 或 false
    Predicate<int> isPrime = n =>
    {
        if (n < 2) return false;  // 小于 2 不是质数
        for (int i = 2; i <= Math.Sqrt(n); i++)
        {
            if (n % i == 0) return false;  // 能被整除不是质数
        }
        return true;  // 其他情况是质数
    };
    // Predicate<int>: 接受 int,返回 bool

    Console.WriteLine("质数检测:");
    Console.WriteLine($"  7 是质数?{isPrime(7)}");   // True
    Console.WriteLine($"  8 是质数?{isPrime(8)}");   // False

    // 2.2 自定义委托
    // (x, y): 两个 int 参数
    // x * y: 返回乘积
    BinaryOperation multiply = (x, y) => x * y;
    // BinaryOperation: 自定义委托,等价于 Func<int, int, int>

    // (x, y): 两个 int 参数
    // (int)Math.Pow(x, y): 计算 x 的 y 次方,转换为 int
    BinaryOperation power = (x, y) => (int)Math.Pow(x, y);

    Console.WriteLine("自定义委托示例:");
    Console.WriteLine($"  5 * 3 = {multiply(5, 3)}");    // 15
    Console.WriteLine($"  2 ^ 8 = {power(2, 8)}");       // 256

    // 2.3 委托链(多播委托)
    // 多个委托可以组合在一起,按顺序执行
    Action? multiAction = () => Console.WriteLine("动作 1");
    // ?: 可空引用类型,允许为 null
    multiAction += () => Console.WriteLine("动作 2");  // 添加第二个动作
    multiAction += () => Console.WriteLine("动作 3");  // 添加第三个动作

    Console.WriteLine("多播委托执行:");
    multiAction();  // 依次执行所有动作

    // 获取委托列表 - 查看委托链中的所有方法
    Delegate[] delegates = multiAction.GetInvocationList();
    Console.WriteLine($"委托链中有 {delegates.Length} 个方法");

    // 移除委托 - 注意:需要相同的引用才能移除
    Action actionToRemove = () => Console.WriteLine("动作 2");
    // 这里不会移除,因为 actionToRemove 是不同的引用实例
    multiAction -= actionToRemove;

    // 2.4 委托作为参数
    // 静态局部方法,接受过滤器和处理器委托
    static void ProcessNumbers(int[] numbers, Func<int, bool> filter, Action<int> processor)
    {
        foreach (int n in numbers)
        {
            if (filter(n))  // 调用过滤器委托
            {
                processor(n);  // 调用处理器委托
            }
        }
    }
    // int[] numbers: 整数数组
    // Func<int, bool> filter: 过滤条件,接受 int 返回 bool
    // Action<int> processor: 处理操作,接受 int 无返回值

    int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    Console.WriteLine("委托作为参数 - 处理偶数:");
    ProcessNumbers(data,
        filter: n => n % 2 == 0,      // Lambda: 判断是否为偶数
        processor: n => Console.WriteLine($"  偶数:{n}"));  // Lambda: 打印

    Console.WriteLine("委托作为参数 - 处理平方数:");
    ProcessNumbers(data,
        filter: n => Math.Sqrt(n) % 1 == 0,  // Lambda: 判断是否为完全平方数
        processor: n => Console.WriteLine($"  平方数:{n}"));
}
#endregion

2.5输出

=== 2. 委托与 Lambda ===

[LOG] 13:25:19: 程序启动
[LOG] 13:25:19: Lambda 演示开始
直角三角形斜边 (3, 4): 5
质数检测:
  7 是质数?True
  8 是质数?False
自定义委托示例:
  5 * 3 = 15
  2 ^ 8 = 256
多播委托执行:
动作 1
动作 2
动作 3
委托链中有 3 个方法
委托作为参数 - 处理偶数:
  偶数:2
  偶数:4
  偶数:6
  偶数:8
  偶数:10
委托作为参数 - 处理平方数:
  平方数:1
  平方数:4
  平方数:9

三.闭包与变量捕获

3.1核心概念

闭包(Closure)指Lambda表达式能够“捕获”其所在作用域中的外部变量,并延长该变量的生命周期。捕获的是变量的引用,而非值的副本

3.2语法结构

Lambda直接使用外部变量。

3.3详细说明与示例

a.基本闭包

示例

int baseValue = 10;
Func addBase = x => x + baseValue; // 捕获baseValue
baseValue = 20; // 修改会影响Lambda
Console.WriteLine(addBase(5)); // 输出25,而非15

特性解析addBase捕获了外部变量baseValue。后续对baseValue的修改会影响已创建的Lambda的行为。

b.循环中的闭包陷阱与解决方案

错误示例badClosures.Add(() => i * 10);// 所有Lambda捕获同一个变量i,最终i=5,所有结果都是50。

正确示例int captured = i; goodClosures.Add(() => captured * 10);// 每次循环创建新变量captured供Lambda捕获。

特性解析:在循环中创建Lambda时,若直接捕获迭代变量,所有Lambda共享该变量的最终值。需在循环内创建局部变量副本再捕获。

c.闭包与状态封装

示例Func CreateCounter = () => { int count = 0; return () => ++count; };

特性解析:工厂函数返回的Lambda捕获了局部变量count。每次调用工厂函数都会创建一个独立的count变量,从而实现多个独立的计数器。这体现了闭包如何用于封装状态。

d.闭包捕获复杂对象:

示例

Func<string> getInfo = () => $"{person.Name} 今年 {person.Age} 岁";

Func<string> getMutableInfo = () => $"{mutablePerson.Name} 今年 {mutablePerson.Age} 岁";

特性解析:由于闭包(Lambda)持有的是同一个对象的引用,所以当通过这个闭包(调用 getMutableInfo())访问对象属性时,它“看到”的是对象最新的、已被修改的状态

3.4例程

#region 3. 闭包与变量捕获

/// <summary>
/// 演示闭包(Closure)与变量捕获的特性
/// 闭包:Lambda 捕获外部变量,延长其生命周期
/// 捕获的是变量的引用,而非值
/// </summary>
static void DemonstrateClosures()
{
    Console.WriteLine();
    Console.WriteLine("=== 3. 闭包与变量捕获 ===");
    Console.WriteLine();

    // 3.1 基本闭包
    Console.WriteLine("3.1 基本闭包:");
    int baseValue = 10;  // 外部变量

    // Lambda 捕获了 baseValue 变量
    // x: Lambda 参数
    // x + baseValue: 使用捕获的外部变量
    Func<int, int> addBase = x => x + baseValue;
    Console.WriteLine($"  addBase(5) = {addBase(5)} (10 + 5)");

    // 修改捕获的变量会影响 Lambda 的行为
    // 因为捕获的是引用,不是值的副本
    baseValue = 20;
    Console.WriteLine($"  addBase(5) = {addBase(5)} (20 + 5)");

    // 3.2 循环中的闭包问题 - 经典陷阱
    Console.WriteLine();
    Console.WriteLine("3.2 循环中的闭包问题:");
    List<Func<int>> badClosures = new List<Func<int>>();
    List<Func<int>> goodClosures = new List<Func<int>>();
    // Func<int>: 无参数,返回 int 的委托

    for (int i = 0; i < 5; i++)
    {
        // 错误的做法 - 所有 Lambda 都引用同一个变量 i
        // 循环结束时 i=5,所有 Lambda 都返回 50
        badClosures.Add(() => i * 10);
        // () => i * 10: 捕获的是变量 i 本身,不是当前值

        // 正确的做法 - 创建局部变量副本
        int captured = i;  // 每次循环创建新变量
        goodClosures.Add(() => captured * 10);
        // () => captured * 10: 捕获的是当前循环的 captured 值
    }

    Console.WriteLine("  错误的闭包结果 (都使用最终的 i 值):");
    foreach (var func in badClosures)
    {
        Console.WriteLine($"    {func()}");  // 都输出 50
    }

    Console.WriteLine("  正确的闭包结果 (捕获时的值):");
    foreach (var func in goodClosures)
    {
        Console.WriteLine($"    {func()}");  // 输出 0, 10, 20, 30, 40
    }

    // 3.3 闭包的内存行为
    Console.WriteLine();
    Console.WriteLine("3.3 闭包的内存行为:");

    // 工厂函数返回一个计数器 Lambda
    Func<Func<int>> CreateCounter = () =>
    {
        int count = 0;  // 局部变量被 Lambda 捕获
        // 返回的 Lambda 捕获了 count 变量
        return () => ++count;
        // () => ++count: 无参数,返回递增后的 count
    };
    // Func<Func<int>>: 返回 Func<int> 的委托

    var counter1 = CreateCounter();  // 创建独立的计数器实例
    var counter2 = CreateCounter();  // 每个实例有自己的 count 变量

    Console.WriteLine("  两个独立的计数器:");
    Console.WriteLine($"  Counter1: {counter1()}, {counter1()}, {counter1()}");  // 1, 2, 3
    Console.WriteLine($"  Counter2: {counter2()}, {counter2()}");                // 1, 2
    Console.WriteLine($"  Counter1: {counter1()}");  // 4(继续计数)
    Console.WriteLine($"  Counter2: {counter2()}");  // 3(继续计数)

    // 3.4 闭包捕获复杂对象
    Console.WriteLine();
    Console.WriteLine("3.4 捕获复杂对象:");

    // 匿名类型 - 属性是只读的
    var person = new { Name = "Alice", Age = 30 };
    // new { Name = ..., Age = ... }: 匿名类型,编译器自动生成类

    Func<string> getInfo = () => $"{person.Name} 今年 {person.Age} 岁";
    // () => ...: 捕获 person 对象的引用
    Console.WriteLine($"  初始:{getInfo()}");

    // 可变对象 - 修改会影响 Lambda
    var mutablePerson = new Person { Name = "Bob", Age = 25 };
    Func<string> getMutableInfo = () => $"{mutablePerson.Name} 今年 {mutablePerson.Age} 岁";
    Console.WriteLine($"  修改前:{getMutableInfo()}");

    mutablePerson.Age = 26;  // 修改对象属性
    Console.WriteLine($"  修改后:{getMutableInfo()}");  // Lambda 看到修改后的值
}
#endregion

3.5输出

=== 3. 闭包与变量捕获 ===

3.1 基本闭包:
  addBase(5) = 15 (10 + 5)
  addBase(5) = 25 (20 + 5)

3.2 循环中的闭包问题:
  错误的闭包结果 (都使用最终的 i 值):
    50
    50
    50
    50
    50
  正确的闭包结果 (捕获时的值):
    0
    10
    20
    30
    40

3.3 闭包的内存行为:
  两个独立的计数器:
  Counter1: 1, 2, 3
  Counter2: 1, 2
  Counter1: 4
  Counter2: 3

3.4 捕获复杂对象:
  初始:Alice 今年 30 岁
  修改前:Bob 今年 25 岁
  修改后:Bob 今年 26 岁

四.LINQ 与 Lambda

4.1核心概念

LINQ(语言集成查询)的方法语法大量依赖Lambda表达式来定义查询、过滤、排序、投影、聚合等操作,其核心是链式调用一系列扩展方法,而 Lambda 表达式则为这些方法提供了关键的操作逻辑,Lambda 以最简洁的形式,就地实现了这些方法所必需的委托参数,使得声明式查询得以在 C# 中以流畅的代码形式表达。

4.2语法结构

集合.操作符(参数 => 表达式)

4.3详细说明与示例

a.基本操作(Where, OrderBy, Select)

示例employees.Where(e => e.Salary > 12000).OrderByDescending(e => e.Salary).Select(e => new { e.Name, e.Salary });

特性解析

e => e.Salary > 12000:作为Where谓词,筛选元素。

e => e.Salary:作为OrderByDescending键选择器,指定排序依据。

e => new { e.Name, e.Salary }:作为Select结果选择器,定义投影形状(匿名类型)。

b.聚合操作(Sum, Average)

示例employees.Sum(e => e.Salary)

特性解析e => e.Salary作为选择器,指定要对哪个字段进行聚合计算。

c.分组操作(GroupBy)

示例employees.GroupBy(e => e.Department)

特性解析e => e.Department作为键选择器,指定按哪个属性进行分组。

d.连接操作(Join)

示例employees.Join(projects, e => e.Id, p => p.LeaderId, (e, p) => new { e.Name, p.Name })

特性解析:使用三个Lambda:e => e.Id(外键)、p => p.LeaderId(内键)、(e, p) => new { … }(结果构造器)。

e.自定义扩展方法

示例employees.TopN(e => e.Salary, 3)

特性解析:展示了如何编写自己的扩展方法(如TopN)来接收Lambda参数(Func keySelector),实现更灵活的查询。

4.4例程

#region 4. LINQ 与 Lambda

/// <summary>
/// 演示 LINQ (Language Integrated Query) 与 Lambda 的结合使用
/// LINQ 方法语法本质上是扩展方法 + Lambda 表达式
/// </summary>
static void DemonstrateLINQAndLambda()
{
    Console.WriteLine();
    Console.WriteLine("=== 4. LINQ 与 Lambda ===");
    Console.WriteLine();

    // 准备测试数据 - 员工列表
    var employees = new List<Employee>
    {
        new Employee { Id = 1, Name = "张三", Department = "研发部", Salary = 15000, Age = 30 },
        new Employee { Id = 2, Name = "李四", Department = "研发部", Salary = 12000, Age = 25 },
        new Employee { Id = 3, Name = "王五", Department = "市场部", Salary = 10000, Age = 28 },
        new Employee { Id = 4, Name = "赵六", Department = "市场部", Salary = 11000, Age = 32 },
        new Employee { Id = 5, Name = "孙七", Department = "人事部", Salary = 9000, Age = 26 },
        new Employee { Id = 6, Name = "周八", Department = "研发部", Salary = 18000, Age = 35 },
        new Employee { Id = 7, Name = "吴九", Department = "财务部", Salary = 13000, Age = 40 },
        new Employee { Id = 8, Name = "郑十", Department = "研发部", Salary = 14000, Age = 29 }
    };

    // 4.1 基本 LINQ 查询

    // 查询语法 - 类似 SQL 的语法风格(语法糖)
    var highSalaryEmployees =
        from e in employees           // 数据源
        where e.Salary > 12000        // 筛选条件
        orderby e.Salary descending   // 排序
        select new { e.Name, e.Salary };  // 投影(选择字段)

    Console.WriteLine("4.1 基本 LINQ 查询:");
    Console.WriteLine("  高薪员工 (查询语法):");
    foreach (var emp in highSalaryEmployees)
    {
        Console.WriteLine($"    {emp.Name}: ¥{emp.Salary:F2}");
    }

    // 方法语法 (Lambda) - 编译器将查询语法转换为此形式
    // .Where(e => e.Salary > 12000)
    // e => e.Salary > 12000: Lambda 作为 Where 方法的参数
    // e: 集合中的每个元素
    // e.Salary > 12000: 返回 bool 的条件表达式
    var highSalaryEmployeesLambda = employees
        .Where(e => e.Salary > 12000)  // Where: 过滤
        .OrderByDescending(e => e.Salary)  // OrderByDescending: 降序排序
        .Select(e => new { e.Name, e.Salary });  // Select: 投影为匿名类型

    Console.WriteLine("  高薪员工 (方法语法/Lambda):");
    highSalaryEmployeesLambda.ToList().ForEach(e =>
        Console.WriteLine($"    {e.Name}: ¥{e.Salary:F2}"));

    // 4.2 聚合操作
    Console.WriteLine();
    Console.WriteLine("4.2 聚合操作:");

    // Sum(e => e.Salary)
    // e => e.Salary: 选择器 Lambda,指定要累加的字段
    double totalSalary = employees.Sum(e => e.Salary);
    // Average(e => e.Salary): 计算平均值
    double avgSalary = employees.Average(e => e.Salary);
    // Max(e => e.Salary): 找最大值
    double maxSalary = employees.Max(e => e.Salary);
    // Min(e => e.Salary): 找最小值
    double minSalary = employees.Min(e => e.Salary);

    Console.WriteLine($"  总工资:¥{totalSalary:F2}");
    Console.WriteLine($"  平均工资:¥{avgSalary:F2}");
    Console.WriteLine($"  最高工资:¥{maxSalary:F2}");
    Console.WriteLine($"  最低工资:¥{minSalary:F2}");

    // 4.3 分组操作
    Console.WriteLine();
    Console.WriteLine("4.3 分组操作:");

    // GroupBy(e => e.Department)
    // e => e.Department: 键选择器 Lambda,按部门分组
    var byDepartment = employees
        .GroupBy(e => e.Department)
        .Select(g => new   // g: IGrouping<string, Employee> 类型
        {
            Department = g.Key,  // 分组键(部门名称)
            Count = g.Count(),  // 该部门人数
            AvgSalary = g.Average(e => e.Salary),  // 平均工资
            Employees = g.Select(e => e.Name).ToList()  // 员工姓名列表
        });

    foreach (var dept in byDepartment)
    {
        Console.WriteLine($"  {dept.Department}: {dept.Count}人,平均工资:¥{dept.AvgSalary:F2}");
        Console.WriteLine($"    员工:{string.Join(", ", dept.Employees)}");
    }

    // 4.4 连接操作
    Console.WriteLine();
    Console.WriteLine("4.4 连接操作:");

    var projects = new List<Project>
    {
        new Project { Id = 1, Name = "ERP 系统", LeaderId = 1 },
        new Project { Id = 2, Name = "移动应用", LeaderId = 2 },
        new Project { Id = 3, Name = "数据分析", LeaderId = 1 }
    };

    // Join 方法签名:
    // Join<TOuter, TInner, TKey, TResult>(
    //     inner,                      // 内层集合
    //     outerKeySelector,          // 外层键选择器
    //     innerKeySelector,          // 内层键选择器
    //     resultSelector             // 结果选择器
    // )
    var employeeProjects = employees
        .Join(projects,
            e => e.Id,              // 外层键选择器:员工的 Id
            p => p.LeaderId,        // 内层键选择器:项目的 LeaderId
            (e, p) => new { e.Name, Project = p.Name });  // 结果选择器 Lambda

    Console.WriteLine("  项目负责人:");
    employeeProjects.ToList().ForEach(ep =>
        Console.WriteLine($"    {ep.Name} -> {ep.Project}"));

    // 4.5 复合查询
    Console.WriteLine();
    Console.WriteLine("4.5 复合查询:");

    // 链式调用多个 LINQ 方法
    var seniorDevelopers = employees
        .Where(e => e.Department == "研发部")  // 筛选研发部
        .Where(e => e.Age >= 30)              // 年龄>=30
        .Where(e => e.Salary >= 15000)        // 工资>=15000
        .OrderByDescending(e => e.Salary)     // 按工资降序
        .ThenBy(e => e.Name)                  // 再按姓名升序
        .Select(e => new
        {
            e.Name,
            e.Age,
            e.Salary,
            SalaryLevel = e.Salary >= 17000 ? "高级" : "中级"  // 三元运算符
        });

    Console.WriteLine("  资深研发人员:");
    seniorDevelopers.ToList().ForEach(e =>
        Console.WriteLine($"    {e.Name}, {e.Age}岁,¥{e.Salary:F2} ({e.SalaryLevel})"));

    // 4.6 自定义扩展方法
    Console.WriteLine();
    Console.WriteLine("4.6 自定义扩展方法:");

    // TopN(e => e.Salary, 3)
    // e => e.Salary: 键选择器 Lambda
    // 3: 取前 3 个
    var top3 = employees.TopN(e => e.Salary, 3);
    Console.WriteLine("  工资 Top3:");
    top3.ToList().ForEach(e =>
        Console.WriteLine($"    {e.Name}: ¥{e.Salary:F2}"));
}
#endregion

4.5输出

=== 4. LINQ 与 Lambda ===

4.1 基本 LINQ 查询:
  高薪员工 (查询语法):
    周八: ¥18000.00
    张三: ¥15000.00
    郑十: ¥14000.00
    吴九: ¥13000.00
  高薪员工 (方法语法/Lambda):
    周八: ¥18000.00
    张三: ¥15000.00
    郑十: ¥14000.00
    吴九: ¥13000.00

4.2 聚合操作:
  总工资:¥102000.00
  平均工资:¥12750.00
  最高工资:¥18000.00
  最低工资:¥9000.00

4.3 分组操作:
  研发部: 4人,平均工资:¥14750.00
    员工:张三, 李四, 周八, 郑十
  市场部: 2人,平均工资:¥10500.00
    员工:王五, 赵六
  人事部: 1人,平均工资:¥9000.00
    员工:孙七
  财务部: 1人,平均工资:¥13000.00
    员工:吴九

4.4 连接操作:
  项目负责人:
    张三 -> ERP 系统
    张三 -> 数据分析
    李四 -> 移动应用

4.5 复合查询:
  资深研发人员:
    周八, 35岁,¥18000.00 (高级)
    张三, 30岁,¥15000.00 (中级)

4.6 自定义扩展方法:
  工资 Top3:
    周八: ¥18000.00
    张三: ¥15000.00
    郑十: ¥14000.00

五.表达式树 (Expression Trees)

5.1核心概念

表达式树将Lambda表达式表示为可检查、可修改的数据结构(树形节点),而非可执行代码。常用于动态构建查询(如Entity Framework)、代码生成等场景。

为什么需要表达式树?(与Lambda委托的关键区别)

委托Lambda:是黑盒。你只能传入参数并得到结果,但无法知道它内部是如何计算的。它是一系列CPU指令。

表达式树Lambda:是白盒,是源代码的抽象语法树。你可以分析、遍历、修改这棵树的节点。然后可以:

编译成委托执行(如上文的 .Compile())。

翻译成其他语言(如SQL)。这是 Entity Framework​ 等ORM框架的核心原理。当在LINQ查询中写 Where(e => e.Salary > 12000)并针对 IQueryable数据源时,这个Lambda会被转换为表达式树。EF Core的提供者会分析这棵树,并将其翻译成 WHERE Salary > 12000这样的SQL语句发送到数据库,而不是在内存中过滤。

5.2语法结构

使用Expression>类型声明,或通过System.Linq.Expressions命名空间下的API动态构建。System.Linq.Expressions.Expression类提供了一系列静态方法,用于以编程方式创建表达式树的各个节点。每个方法都返回一个从 Expression派生的特定节点类型对象,这些对象共同构成一棵描述代码逻辑的树。

a.Expression.Parameter

作用:创建一个表示 Lambda 表达式参数​ 的节点。

文档示例ParameterExpression paramX = Expression.Parameter(typeof(int), “x”);

解析:此方法定义了一个变量(如 x),并指定其类型(typeof(int))和可选名称(“x””)。它是构建Lambda表达式树的起点,代表输入的占位符。

b.Expression.Constant

作用:创建一个表示 常量值​ 的节点。

文档示例ConstantExpression constant2 = Expression.Constant(2, typeof(int));

解析:此方法将一个字面量(如数字2、字符串“Hello”)封装为表达式树中的一个叶子节点。它代表计算中不变的部分。

c.Expression.Add/ Expression.Multiply

作用:创建表示 算术运算​ 的二元表达式节点。Add为加法,Multiply为乘法。同类方法还有 Subtract(减)、Divide(除)等。

文档示例BinaryExpression addBody = Expression.Add(paramX, paramY);(构建 x + y

解析:这些方法接收左、右两个表达式节点作为子节点,并返回一个新的二元运算节点。它们是构建复杂计算逻辑的桥梁。

d.Expression.GreaterThan/ Expression.LessThan

作用:创建表示 关系比较​ 的二元表达式节点。GreaterThan为“大于”,LessThan为“小于”。

文档示例(5.3节):BinaryExpression greaterThan = Expression.GreaterThan(paramNum, zero);(构建 num > 0

解析:与算术运算类似,它们比较两个子表达式的结果,返回一个表示 bool类型比较结果的节点。

e.Expression.AndAlso

作用:创建表示 逻辑“与”​ 运算的二元表达式节点。它对应C#中的 &&运算符,支持短路求值(一旦能够根据左侧操作数的值确定整个表达式的结果,就会立即停止计算,不再对右侧操作数进行求值。)。

文档示例(5.6节):BinaryExpression andExpression = Expression.AndAlso(ageGreaterThan20, ageLessThan30);(构建 ... && ...

解析:用于组合两个返回 bool的表达式节点,形成逻辑与条件。

f.Expression.Call

作用:创建一个表示 实例方法或静态方法调用​ 的节点。

文档示例(5.4节):MethodCallExpression toUpperCall = Expression.Call(paramStr, toUpperMethod);(构建 s.ToUpper()

解析:此方法需要指定方法所属的对象实例(对于实例方法)、要调用的方法的 MethodInfo(通过反射获得),以及方法的参数列表。它用于在表达式树中嵌入方法调用逻辑。

g.Expression.Lambda

作用:将一系列表达式节点封装成一个完整的、可编译的 Lambda 表达式树

文档示例Expression> multiplyExpr = Expression.Lambda>(multiplyBody, paramX, paramY);

解析:这是构建过程的最后一步。它接收一个表达式体(如 multiplyBody)和一组参数定义(如 paramX, paramY),将它们组合成一个代表匿名函数的 Expression对象。此对象可以进行分析、修改,或通过 .Compile()方法编译成可执行的委托。

5.3详细说明与示例

a.声明表达式树

示例Expression> addExpr = (x, y) => x + y;

特性解析:与委托Lambda相似,但类型是Expression>。它可以被编译成委托执行(addExpr.Compile()(3,5)),也可以被分析其结构。

b.动态构建表达式树

示例

ParameterExpression paramX = Expression.Parameter(typeof(int), “x”);
BinaryExpression addBody = Expression.Add(paramX, Expression.Constant(2));
Expression> addTwoExpr = Expression.Lambda>(addBody, paramX);

特性解析:通过Expression类的静态方法(Parameter, Add, Constant, Lambda)手动构建一个表示x => x + 2的表达式树。这展示了表达式树作为数据结构的本质。

c.在IQueryable查询中的应用

示例people.AsQueryable().Where(filterExpr);filterExpr是一个Expression>

特性解析IQueryable提供者(如EF Core)可以解析filterExpr这个表达式树,将其转换为特定的查询语言(如SQL),而不是在内存中过滤。这是LINQ to SQL等技术的基石。

5.4例程

#region 5. 表达式树 (Expression Trees)

/// <summary>
/// 演示表达式树(Expression Tree)的创建和使用
/// 表达式树:将 Lambda 表达式表示为数据结构(而非可执行代码)
/// 可用于动态修改代码、ORM 框架(如 Entity Framework)等
/// </summary>
static void DemonstrateExpressionTrees()
{
    Console.WriteLine();
    Console.WriteLine("=== 5. 表达式树 (Expression Trees) ===");
    Console.WriteLine();

    // 5.1 创建简单表达式树
    Console.WriteLine("5.1 创建简单表达式树:");

    // ParameterExpression: 表示 Lambda 的参数
    // typeof(int): 参数类型
    // "x": 参数名称
    ParameterExpression paramX = Expression.Parameter(typeof(int), "x");
    ParameterExpression paramY = Expression.Parameter(typeof(int), "y");

    // BinaryExpression: 表示二元运算(如加法)
    // Expression.Add: 创建加法表达式节点
    BinaryExpression addBody = Expression.Add(paramX, paramY);
    // 这构建了表达式树的主体:x + y

    // Expression.Lambda: 将表达式体和参数组合成 Lambda
    // Func<int, int, int>: Lambda 的委托类型
    Expression<Func<int, int, int>> addExpr =
        Expression.Lambda<Func<int, int, int>>(addBody, paramX, paramY);

    // Compile(): 将表达式树编译为可执行的委托
    Func<int, int, int> addFunc = addExpr.Compile();
    Console.WriteLine($"  表达式树:{addExpr}");
    Console.WriteLine($"  计算结果:3 + 5 = {addFunc(3, 5)}");

    // 5.2 动态构建复杂表达式
    Console.WriteLine();
    Console.WriteLine("5.2 动态构建复杂表达式:");

    // 构建表达式:(x, y) => (x + y) * 2
    BinaryExpression addExpr2 = Expression.Add(paramX, paramY);  // x + y
    ConstantExpression constant2 = Expression.Constant(2, typeof(int));  // 常量 2
    BinaryExpression multiplyBody = Expression.Multiply(addExpr2, constant2);  // (x+y) * 2

    Expression<Func<int, int, int>> multiplyExpr =
        Expression.Lambda<Func<int, int, int>>(multiplyBody, paramX, paramY);

    Func<int, int, int> multiplyFunc = multiplyExpr.Compile();
    Console.WriteLine($"  表达式树:{multiplyExpr}");
    Console.WriteLine($"  计算结果:(3 + 5) * 2 = {multiplyFunc(3, 5)}");

    // 5.3 条件表达式
    Console.WriteLine();
    Console.WriteLine("5.3 条件表达式:");

    // 构建表达式:num => (num > 0 ? "正数" : "非正数")
    ParameterExpression paramNum = Expression.Parameter(typeof(int), "num");

    ConstantExpression zero = Expression.Constant(0, typeof(int));  // 常量 0
    BinaryExpression greaterThan = Expression.GreaterThan(paramNum, zero);  // num > 0

    ConstantExpression positive = Expression.Constant("正数", typeof(string));
    ConstantExpression nonPositive = Expression.Constant("非正数", typeof(string));

    // ConditionalExpression: 三元运算符
    // 如果 greaterThan 为 true,返回 positive,否则返回 nonPositive
    ConditionalExpression conditional = Expression.Condition(greaterThan, positive, nonPositive);

    Expression<Func<int, string>> checkExpr =
        Expression.Lambda<Func<int, string>>(conditional, paramNum);

    Func<int, string> checkFunc = checkExpr.Compile();
    Console.WriteLine($"  表达式树:{checkExpr}");
    Console.WriteLine($"  checkFunc(5) = {checkFunc(5)}");
    Console.WriteLine($"  checkFunc(-3) = {checkFunc(-3)}");
    Console.WriteLine($"  checkFunc(0) = {checkFunc(0)}");

    // 5.4 方法调用表达式
    Console.WriteLine();
    Console.WriteLine("5.4 方法调用表达式:");

    // 构建表达式:s => s.ToUpper()
    ParameterExpression paramStr = Expression.Parameter(typeof(string), "s");

    // 获取 ToUpper 方法的 MethodInfo(反射)
    MethodInfo toUpperMethod = typeof(string).GetMethod("ToUpper", Type.EmptyTypes)
        ?? throw new InvalidOperationException("未找到 ToUpper 方法");

    // MethodCallExpression: 方法调用表达式
    // Expression.Call: 创建方法调用节点
    MethodCallExpression toUpperCall = Expression.Call(paramStr, toUpperMethod);

    Expression<Func<string, string>> toUpperExpr =
        Expression.Lambda<Func<string, string>>(toUpperCall, paramStr);

    Func<string, string> toUpperFunc = toUpperExpr.Compile();
    Console.WriteLine($"  'hello' -> '{toUpperFunc("hello")}'");

    // 5.5 动态构建查询表达式
    Console.WriteLine();
    Console.WriteLine("5.5 动态构建查询表达式:");

    var people = new List<Person>
    {
        new Person { Name = "Alice", Age = 30 },
        new Person { Name = "Bob", Age = 25 },
        new Person { Name = "Charlie", Age = 35 },
        new Person { Name = "David", Age = 20 }
    };

    // 动态构建表达式:p => p.Age > 25
    ParameterExpression paramPerson = Expression.Parameter(typeof(Person), "p");

    // MemberExpression: 访问属性/字段
    // Expression.Property: 创建属性访问节点
    MemberExpression ageProperty = Expression.Property(paramPerson, "Age");

    ConstantExpression age25 = Expression.Constant(25, typeof(int));
    BinaryExpression ageGreaterThan25 = Expression.GreaterThan(ageProperty, age25);

    Expression<Func<Person, bool>> filterExpr =
        Expression.Lambda<Func<Person, bool>>(ageGreaterThan25, paramPerson);

    Console.WriteLine($"  动态构建的过滤器:{filterExpr}");

    // AsQueryable(): 将集合转换为 IQueryable,支持表达式树
    // Where(filterExpr): 使用表达式树作为过滤条件
    var adults = people.AsQueryable().Where(filterExpr);
    Console.WriteLine("  年龄大于 25 的人:");
    adults.ToList().ForEach(p => Console.WriteLine($"    {p.Name} ({p.Age}岁)"));

    // 5.6 组合表达式
    Console.WriteLine();
    Console.WriteLine("5.6 组合表达式:");

    // 构建表达式:p => p.Age > 20 && p.Age < 30
    ConstantExpression age20 = Expression.Constant(20, typeof(int));
    ConstantExpression age30 = Expression.Constant(30, typeof(int));

    BinaryExpression ageGreaterThan20 = Expression.GreaterThan(ageProperty, age20);
    BinaryExpression ageLessThan30 = Expression.LessThan(ageProperty, age30);

    // AndAlso: 逻辑与 (&&),短路求值
    BinaryExpression andExpression = Expression.AndAlso(ageGreaterThan20, ageLessThan30);

    Expression<Func<Person, bool>> ageRangeExpr =
        Expression.Lambda<Func<Person, bool>>(andExpression, paramPerson);

    Console.WriteLine($"  组合表达式:{ageRangeExpr}");

    var youngAdults = people.AsQueryable().Where(ageRangeExpr);
    Console.WriteLine("  年龄 20-30 之间的人:");
    youngAdults.ToList().ForEach(p => Console.WriteLine($"    {p.Name} ({p.Age}岁)"));
}
#endregion

5.5输出

=== 5. 表达式树 (Expression Trees) ===

5.1 创建简单表达式树:
  表达式树:(x, y) => (x + y)
  计算结果:3 + 5 = 8

5.2 动态构建复杂表达式:
  表达式树:(x, y) => ((x + y) * 2)
  计算结果:(3 + 5) * 2 = 16

5.3 条件表达式:
  表达式树:num => IIF((num > 0), "正数", "非正数")
  checkFunc(5) = 正数
  checkFunc(-3) = 非正数
  checkFunc(0) = 非正数

5.4 方法调用表达式:
  'hello' -> 'HELLO'

5.5 动态构建查询表达式:
  动态构建的过滤器:p => (p.Age > 25)
  年龄大于 25 的人:
    Alice (30岁)
    Charlie (35岁)

5.6 组合表达式:
  组合表达式:p => ((p.Age > 20) AndAlso (p.Age < 30))
  年龄 20-30 之间的人:
    Bob (25岁)

六.事件与 Lambda

6.1核心概念

事件是基于委托的发布-订阅模型。Lambda表达式可以简洁地定义事件处理程序(订阅者)。

6.2语法结构

事件对象.事件名 += (sender, eventArgs) => { … };

6.3详细说明与示例

a.订阅事件

示例processor.DataReceived += (sender, data) => Console.WriteLine($“收到数据:{data}”);

特性解析:使用Lambda快速定义一个匿名事件处理方法。sender是事件源,data是事件参数。

b.取消订阅

注意:若要取消订阅,必须保存Lambda的引用。-=需要完全相同的委托实例,而匿名Lambda每次都是新实例。

示例

EventHandler specificHandler = (sender, data) => { … };
processor.DataReceived += specificHandler; // 订阅
processor.DataReceived -= specificHandler; // 取消订阅(有效)

c.Lambda vs 匿名方法

Lambda示例processor.DataReceived += (sender, data) => { … };

匿名方法示例processor.DataReceived += delegate (object? sender, string data) { … };

特性解析:Lambda是更现代、简洁的语法。匿名方法是C# 2.0的语法,需要delegate关键字和显式参数类型声明。

6.4例程

#region 6. 事件与 Lambda

/// <summary>
/// 演示事件(Event)与 Lambda 表达式的结合使用
/// 事件是基于委托的发布 - 订阅模式实现
/// Lambda 简化了事件处理器的编写
/// </summary>
static void DemonstrateEventsAndLambda()
{
    Console.WriteLine();
    Console.WriteLine("=== 6. 事件与 Lambda ===");
    Console.WriteLine();

    // 6.1 事件定义
    var processor = new DataProcessor();

    // 6.2 Lambda 事件处理器
    Console.WriteLine("6.2 Lambda 事件处理器:");

    // 使用 Lambda 订阅事件
    // 当 DataProcessor接收到新数据时,触发此事件,通知所有订阅者。
    // 通过 +=运算符,Lambda 被注册(订阅)到对应的事件“频道”上。当事件被触发时,所有订阅的 Lambda 会自动执行,做出响应。
    // (sender, data): 事件处理器的两个参数
    // sender: 事件发送者(通常是 this)
    // data: 事件数据
    processor.DataReceived += (sender, data) =>
    {
        Console.WriteLine($"  [Lambda] 收到数据:{data}");
    };
    // +=: 订阅事件(添加委托到 invocation list)

    // 另一个事件处理器
    // 当 DataProcessor完成对一批数据的处理后,触发此事件,通知订阅者处理结果。
    processor.DataProcessed += (sender, e) =>
    {
        Console.WriteLine($"  [Lambda] 数据处理完成:{e.Result}");
    };
    // e: ProcessingEventArgs 类型的事件参数对象

    // 6.3 处理带参数的事件
    // 在数据处理过程中,定期触发此事件以报告当前进度。
    // progress: int 类型的进度值(0-100)
    processor.ProgressChanged += (sender, progress) =>
    {
        if (progress % 20 == 0)  // 每 20% 报告一次
        {
            Console.WriteLine($"  [Lambda] 处理进度:{progress}%");
        }
    };

    // 6.4 取消事件订阅
    // 先保存引用,以便后续取消订阅
    EventHandler<string> specificHandler = (sender, data) =>
    {
        Console.WriteLine($"  [特定处理器] 数据:{data}");
    };

    processor.DataReceived += specificHandler;  // 订阅

    // 6.5 触发事件
    Console.WriteLine("触发事件:");
    //模拟进度
    processor.StartProcessing("测试数据 123");

    // 6.6 取消订阅
    // -=: 从事件的 invocation list 中移除委托
    processor.DataReceived -= specificHandler;
    Console.WriteLine("移除特定处理器后再次触发:");
    processor.StartProcessing("新数据 456");

    // 6.7 匿名方法 vs Lambda
    Console.WriteLine();
    Console.WriteLine("6.7 匿名方法 vs Lambda:");

    // 匿名方法 (C# 2.0) - 较旧的语法
    processor.DataReceived += delegate (object? sender, string data)
    {
        Console.WriteLine($"  [匿名方法] 数据:{data}");
    };
    // delegate: 匿名方法关键字
    // (object? sender, string data): 显式指定参数类型
    // ?: 可空引用类型

    // Lambda 表达式 (C# 3.0+) - 更简洁的语法
    processor.DataReceived += (sender, data) =>
    {
        Console.WriteLine($"  [Lambda] 数据:{data}");
    };

    processor.ProcessSingleData("比较数据");

    // 6.8 自定义事件参数
    Console.WriteLine();
    Console.WriteLine("6.8 自定义事件参数:");

    var sensor = new Sensor();

    // ReadingChanged 事件携带详细的事件参数
    sensor.ReadingChanged += (sender, e) =>
    {
        Console.WriteLine($"  传感器读数变化:{e.OldValue} -> {e.NewValue}");
        Console.WriteLine($"  变化时间:{e.ChangeTime}");
    };
    // e: ReadingChangedEventArgs 类型
    // e.OldValue: 旧值
    // e.NewValue: 新值
    // e.ChangeTime: 变更时间

    // 修改属性会触发事件
    sensor.Reading = 25.5;
    sensor.Reading = 26.0;
    sensor.Reading = 25.8;
}
#endregion

6.5输出

=== 6. 事件与 Lambda ===

6.2 Lambda 事件处理器:
触发事件:
  [Lambda] 收到数据:测试数据 123
  [特定处理器] 数据:测试数据 123
  [Lambda] 处理进度:0%
  [Lambda] 处理进度:20%
  [Lambda] 处理进度:40%
  [Lambda] 处理进度:60%
  [Lambda] 处理进度:80%
  [Lambda] 处理进度:100%
  [Lambda] 数据处理完成:处理结果:测试数据 123
移除特定处理器后再次触发:
  [Lambda] 收到数据:新数据 456
  [Lambda] 处理进度:0%
  [Lambda] 处理进度:20%
  [Lambda] 处理进度:40%
  [Lambda] 处理进度:60%
  [Lambda] 处理进度:80%
  [Lambda] 处理进度:100%
  [Lambda] 数据处理完成:处理结果:新数据 456

6.7 匿名方法 vs Lambda:
  [Lambda] 收到数据:比较数据
  [匿名方法] 数据:比较数据
  [Lambda] 数据:比较数据

6.8 自定义事件参数:
  传感器读数变化:0 -> 25.5
  变化时间:2026/3/16 13:25:20
  传感器读数变化:25.5 -> 26
  变化时间:2026/3/16 13:25:20
  传感器读数变化:26 -> 25.8
  变化时间:2026/3/16 13:25:20

七.异步 Lambda

7.1核心概念

使用asyncawait关键字定义的Lambda,用于表示异步操作。其返回类型通常是TaskTask

async关键字:声明与“赋能”
作用:它用于修饰一个方法或Lambda表达式,将其标记为一个“异步方法”。这是使用 await关键字的前提条件。它告诉编译器:“我这个方法内部将使用 await来进行异步等待,请为我生成必要的状态机代码来处理方法的暂停和恢复。”

await关键字:等待与“让权”
作用:它用于等待一个异步操作(通常是 Task或 Task<T>)完成。这是实现“异步”行为的核心操作。它是实际执行异步等待的指令。await只能出现在用 async修饰的方法或Lambda内部

7.2语法结构

async (参数) => { await 异步操作; … }

7.3详细说明与示例

a.异步Lambda声明

示例Func> fetchDataAsync = async (id) => { await Task.Delay(100); return $“数据-{id}”; };

特性解析:Lambda前加async关键字,内部使用await等待异步操作。其类型是返回TaskFunc委托。

b.异步事件处理器

示例asyncProcessor.ProcessingStarted += async (sender, fileName) => { await Task.Delay(50); … };

特性解析:事件类型可以是Func<object, T, Task>,允许用异步Lambda作为事件处理程序。

c.在LINQ Select中模拟异步转换

示例numbers.Select(async n => { await Task.Delay(1000); return n * n; });

特性解析Select内的Lambda可以是异步的,返回Task。之后需通过Task.WhenAll或异步流(IAsyncEnumerable)来处理结果。

整个 Select操作的结果是一个 IEnumerable<Task<int>>,即一个包含10个“已启动但尚未完成”的 Task的集合。此时,所有模拟的“异步计算”都已经在后台运行了。
由于 IEnumerable 的延迟执行特性,Select 只是定义了转换规则,真正的数据处理(如遍历、计算、转换)会延迟到实际需要消费数据的那一刻(即首次对序列进行枚举时)才会发生。

d.协作式取消令牌

示例

using (var cts = new System.Threading.CancellationTokenSource())
{
    CancellationToken cancellationToken = cts.Token;
    try
    {
        await Task.Run(async () =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            ...
        }, cancellationToken);  // 传递取消令牌
    }
}

特性解析

其原理基于两个核心类的协作:CancellationTokenSource(取消请求的发起者)和 CancellationToken(取消信号的传递载体)。整个过程是“请求-检测-响应”的协作式模型,而非强制中断线程。

事件的顺序:
T=0ms: 任务启动,进入第一次循环,打印处理中... 1,然后 await Task.Delay(100)。
T=100ms: 第一次 Task.Delay完成,进入第二次循环,打印处理中... 2,再次开始 await Task.Delay(100)。
T=200ms: 第二次 Task.Delay完成,进入第三次循环,打印处理中... 3,开始第三次 Task.Delay(100)。
T=250ms: 定时器触发!cts.Cancel()被调用,cts.Token的状态变为“已取消”。
T=300ms: 第三次 Task.Delay完成。当代码尝试继续执行,回到循环顶部,执行 cts.Token.ThrowIfCancellationRequested()时,该方法检测到令牌已取消,立即抛出 OperationCanceledException。
循环被强行中断,任务因异常而结束。异常被外层 catch块捕获,打印操作被取消。

7.4例程

#region 7. 异步 Lambda

/// <summary>
/// 演示异步 Lambda 表达式的使用
/// async: 标记方法为异步
/// await: 等待异步操作完成
/// Task: 表示异步操作的返回类型
/// </summary>
/// <returns>异步任务(Task)</returns>
static async Task DemonstrateAsyncLambda()
{
    Console.WriteLine();
    Console.WriteLine("=== 7. 异步 Lambda ===");
    Console.WriteLine();

    // 7.1 异步 Lambda 表达式
    Console.WriteLine("7.1 异步 Lambda 表达式:");

    // async (id) => { ... }: 异步 Lambda
    // async: 使 Lambda 成为异步方法
    // (id): Lambda 参数
    // Task<string>: 返回类型
    Func<int, Task<string>> fetchDataAsync = async (id) =>
    {
        Console.WriteLine($"  开始获取数据 {id}...");
        await Task.Delay(100);  // 异步等待 100ms
        // await: 暂停执行直到 Task 完成,不阻塞线程,控制权返回给调用者
        //大约100毫秒后,Task.Delay完成。系统会(可能在原线程,也可能在新线程)恢复执行​ fetchDataAsync剩余的代码
        Console.WriteLine($"  数据 {id} 获取完成");
        return $"数据-{id}";  // 返回结果
    };

    // 调用异步 Lambda
    // await: 等待异步操作完成
    string result1 = await fetchDataAsync(1);
    string result2 = await fetchDataAsync(2);

    Console.WriteLine($"  结果:{result1}, {result2}");

    // 7.2 并行异步操作
    Console.WriteLine();
    Console.WriteLine("7.2 并行异步操作:");

    var tasks = new List<Task<string>>();
    for (int i = 1; i <= 5; i++)
    {
        int id = i;  // 创建局部变量副本,避免闭包问题
        // Task.Run: 在线程池中运行异步操作
        // 启动任务,但不立即await。此时所有Task几乎同时开始运行。
        tasks.Add(Task.Run(async () =>
        {
            await Task.Delay(id * 100);  // 模拟不同耗时的操作
            return $"结果-{id}";
        }));
    }

    // Task.WhenAll: 同时等待多个异步任务全部完成。它接收一个任务集合(如 Task[]或 Task<T>[]),并返回一个新的聚合任务。
    var results = await Task.WhenAll(tasks);
    Console.WriteLine($"  并行结果:{string.Join(", ", results)}");

    // 7.3 异步事件处理器
    Console.WriteLine();
    Console.WriteLine("7.3 异步事件处理器:");

    var asyncProcessor = new AsyncProcessor();

    // 异步事件处理器 - Lambda 中使用 async/await
    asyncProcessor.ProcessingStarted += async (sender, fileName) =>
    {
        Console.WriteLine($"  开始处理:{fileName}");
        await Task.Delay(50);
        Console.WriteLine($"  预处理完成:{fileName}");
    };

    asyncProcessor.ProcessingCompleted += async (sender, result) =>
    {
        Console.WriteLine($"  处理结果:{result}");
        await Task.Delay(50);
        Console.WriteLine($"  结果已记录");
    };

    await asyncProcessor.ProcessFileAsync("data.csv");

    // 7.4 异步 LINQ
    Console.WriteLine();
    Console.WriteLine("7.4 异步 LINQ:");

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

    // 异步 Select - 每个元素的转换都是异步的
    // async n => { ... }: 异步 Lambda
    // 整个 Select操作的结果是一个 IEnumerable<Task<int>>,即一个包含10个“已启动但尚未完成”的 Task的集合。此时,所有模拟的“异步计算”都已经在后台运行了。
    // 由于 IEnumerable 的延迟执行特性,Select 只是定义了转换规则,真正的数据处理(如遍历、计算、转换)会延迟到实际需要消费数据的那一刻(即首次对序列进行枚举时)才会发生。
    var asyncSquares = numbers.Select(async n =>
    {
        await Task.Delay(1000);
        return n * n;
    }).ToList();  // 强制立即枚举,启动所有 Task
    Thread.Sleep(1000);
    Console.WriteLine("  异步计算平方:");
    // await foreach: 遍历执行异步 enumerable
    await foreach (var square in ToAsyncEnumerable(asyncSquares))
    {
        Console.WriteLine($"    {square}");//在这里取结果前应该已经计算完成,一下子全部打印出来
    }

    // 7.5 取消令牌
    Console.WriteLine();
    Console.WriteLine("7.5 取消令牌:");

    using (var cts = new System.Threading.CancellationTokenSource())
    {
        // CancelAfter: 指定时间后自动取消
        cts.CancelAfter(250);  // 250ms 后取消
        // 获取取消令牌 (CancellationToken) - 信号载体
        CancellationToken cancellationToken = cts.Token;
        try
        {
            await Task.Run(async () =>
            {
                for (int i = 0; i < 10; i++)
                {
                    // ThrowIfCancellationRequested: 检查是否被取消
                    cancellationToken.ThrowIfCancellationRequested();
                    Console.WriteLine($"  处理中... {i + 1}");
                    await Task.Delay(100);
                }
            }, cancellationToken);  // 传递取消令牌
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("  操作被取消");
        }
    }
}

/// <summary>
/// 辅助方法:将 Task 集合转换为异步枚举
/// IAsyncEnumerable<T>: 异步可枚举接口
/// yield return: 迭代器返回
/// </summary>
/// <typeparam name="T">元素类型</typeparam>
/// <param name="tasks">任务集合</param>
/// <returns>异步枚举器</returns>
static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(IEnumerable<Task<T>> tasks)
{
    foreach (var task in tasks)
    {
        //yield return:它告诉编译器,当调用方迭代此方法返回的序列时,每次遇到 yield return,就立即将后面的表达式(await task的结果)作为当前元素返回给调用方,并暂停当前方法的执行,保存所有局部状态。
        //下次迭代时,方法会从上次暂停的地方(yield return语句之后)直接恢复执行,继续循环,处理下一个任务,直到没有更多元素。
        yield return await task;  // 逐个返回完成的任务结果
    }
}
#endregion

7.5输出

=== 7. 异步 Lambda ===

7.1 异步 Lambda 表达式:
  开始获取数据 1...
  数据 1 获取完成
  开始获取数据 2...
  数据 2 获取完成
  结果:数据-1, 数据-2

7.2 并行异步操作:
  并行结果:结果-1, 结果-2, 结果-3, 结果-4, 结果-5

7.3 异步事件处理器:
  开始处理:data.csv
  预处理完成:data.csv
  处理结果:data.csv 处理完成,大小:1024KB
  结果已记录

7.4 异步 LINQ:
  异步计算平方:
    1
    4
    9
    16
    25
    36
    49
    64
    81
    100

7.5 取消令牌:
  处理中... 1
  处理中... 2
  处理中... 3
  操作被取消

八.高级用法

8.1核心概念

介绍函数式编程风格的高级Lambda用法。

8.2详细说明与示例

a.递归Lambda

示例

Func? factorial = null;
factorial = n => n <= 1 ? 1 : n * factorial!(n - 1);

特性解析:Lambda需先声明为可空变量,再在定义中通过factorial!调用自身(使用非空断言!)。

b.高阶函数(函数作为输入输出)

示例Func> multiplierFactory = factor => x => x * factor;

特性解析multiplierFactory是一个返回Lambda的Lambda(高阶函数)。factor被内层Lambda捕获,实现了“工厂”模式。

c.柯里化

示例Func> addCurried = a => b => c => a + b + c;

特性解析:将多参数函数转换为一系列单参数函数的链式调用。addCurried(5)(3)(2)等价于(5,3,2)=>5+3+2

d.函数组合

示例Func composed = addOne.Compose(multiplyByTwo).Compose(square2);

特性解析:通过自定义的Compose扩展方法,将多个Lambda(函数)组合成一个新的函数,执行顺序是从左到右。

e.记忆化

示例if (memo.TryGetValue(n, out var value)) return value;

特性解析:记忆化示例巧妙地将Lambda的闭包特性(用于维持共享的缓存状态)与递归能力(实现算法逻辑)结合在一起。闭包提供了跨调用持久化“记忆”的能力,而递归Lambda则利用这份“记忆”来避免重复计算,二者协同实现了性能优化。这一切都建立在Lambda可以作为委托实例灵活使用的特性之上。

f.模式匹配

示例Func<object, string> describe = obj => obj switch{...};

特性解析:switch表达式是 C# 8.0 引入的增强模式匹配语法,它对一个输入表达式 (obj)​ 进行匹配,并根据匹配到的模式返回一个结果值。整个表达式本身会产出一个值,可以用于赋值或返回。相比传统的 if-elseswitch语句,switch表达式语法更简洁、声明式,能直接返回值,并且通过模式匹配提供了更强大的类型检查和提取能力。

8.3例程

#region 8. 高级主题

/// <summary>
/// 演示 Lambda 的高级用法和函数式编程概念
/// </summary>
static void DemonstrateAdvancedTopics()
{
    Console.WriteLine();
    Console.WriteLine("=== 8. 高级主题 ===");
    Console.WriteLine();

    // 8.1 递归 Lambda
    Console.WriteLine("8.1 递归 Lambda:");

    // 递归 Lambda 需要特殊处理
    // Func<int, int>?: 可空的委托类型
    Func<int, int>? factorial = null;
    // 先声明变量,再赋值,以便在 Lambda 内部引用自身
    factorial = n => n <= 1 ? 1 : n * factorial!(n - 1);
    // n: 输入参数
    // n <= 1 ? 1 : ...: 三元运算符,基本情况
    // factorial!(n - 1): 递归调用,! 是非空断言
    // 因为编译器不知道 factorial 在此时一定不为 null

    Console.WriteLine($"  阶乘 5! = {factorial(5)}");   // 120
    Console.WriteLine($"  阶乘 10! = {factorial(10)}"); // 3628800

    // 8.2 Lambda 作为返回值(工厂模式)
    Console.WriteLine();
    Console.WriteLine("8.2 Lambda 作为返回值:");

    // 高阶函数:返回函数的函数
    // factor: 外层 Lambda 参数
    // x => x * factor: 内层 Lambda,捕获 factor
    Func<int, Func<int, int>> multiplierFactory = factor => x => x * factor;
    // Func<int, Func<int, int>>:
    // 第一个 int: factor 参数类型
    // Func<int, int>: 返回的 Lambda 类型

    var doubleIt = multiplierFactory(2);  // 创建乘以 2 的函数
    // doubleIt 等价于:x => x * 2
    var tripleIt = multiplierFactory(3);  // 创建乘以 3 的函数
                                          // tripleIt 等价于:x => x * 3

    Console.WriteLine($"  doubleIt(5) = {doubleIt(5)}");  // 10
    Console.WriteLine($"  tripleIt(5) = {tripleIt(5)}");  // 15

    // 8.3 柯里化(Currying)
    Console.WriteLine();
    Console.WriteLine("8.3 柯里化:");

    // 柯里化:将多参数函数转换为一系列单参数函数
    // a => b => c => a + b + c
    // 读作:a => (b => (c => a + b + c))
    Func<int, Func<int, Func<int, int>>> addCurried = a => b => c => a + b + c;

    var add5 = addCurried(5);    // 固定第一个参数为 5,返回 b => c => 5 + b + c
    var add5And3 = add5(3);      // 固定第二个参数为 3,返回 c => 5 + 3 + c
    var result = add5And3(2);    // 传入第三个参数,返回 5 + 3 + 2 = 10

    Console.WriteLine($"  柯里化加法:5 + 3 + 2 = {result}");
    Console.WriteLine($"  直接调用:{addCurried(5)(3)(2)}");

    // 8.4 组合函数(Function Composition)
    Console.WriteLine();
    Console.WriteLine("8.4 组合函数:");

    // 定义基础函数
    Func<int, int> addOne = x => x + 1;         // f(x) = x + 1
    Func<int, int> multiplyByTwo = x => x * 2;  // g(x) = x * 2
    Func<int, int> square2 = x => x * x;        // h(x) = x²

    // 手动组合:h(g(f(x)))
    // x => multiplyByTwo(addOne(x)): 先加 1,再乘 2
    Func<int, int> addThenMultiply = x => multiplyByTwo(addOne(x));

    // 使用扩展方法组合
    // addOne.Compose(multiplyByTwo): 先执行 addOne,再执行 multiplyByTwo
    // .Compose(square2): 再执行 square2
    Func<int, int> composed = addOne.Compose(multiplyByTwo).Compose(square2);
    // 最终效果:((x + 1) * 2)²

    Console.WriteLine($"  addThenMultiply(3) = {addThenMultiply(3)}");  // (3+1)*2 = 8
    Console.WriteLine($"  composed(3) = {composed(3)}");  // ((3+1)*2)² = 64

    // 8.5 记忆化(Memoization)
    Console.WriteLine();
    Console.WriteLine("8.5 记忆化:");

    // 带记忆化的斐波那契数列
    Func<long, long>? fibonacci = null;
    var memo = new Dictionary<long, long>();  // 缓存字典

    fibonacci = n =>
    {
        // TryGetValue: 尝试获取缓存值
        // n: 键
        // out var value: 输出的值
        // 如果存在缓存,直接返回,避免重复计算
        if (memo.TryGetValue(n, out var value)) return value;

        if (n <= 2) return 1;  // 基本情况:F(1)=1, F(2)=1

        // 递归计算并缓存
        var result = fibonacci!(n - 1) + fibonacci!(n - 2);
        memo[n] = result;  // 存入缓存
        return result;
    };

    Console.WriteLine($"  斐波那契数列:");
    for (int i = 1; i <= 10; i++)
    {
        Console.WriteLine($"    F({i}) = {fibonacci(i)}");
    }

    // 8.6 模式匹配(Pattern Matching)
    Console.WriteLine();
    Console.WriteLine("8.6 模式匹配:");

    // switch 表达式(C# 8.0+)
    // obj switch { ... }: 对 obj 进行模式匹配
    Func<object, string> describe = obj => obj switch
    {
        int i when i > 0 => $"正整数:{i}",      // 类型模式 + 条件
        int i when i < 0 => $"负整数:{i}",      // 类型模式 + 条件
        int i => $"零:{i}",                     // 类型模式
        string s => $"字符串:'{s}'",            // 类型模式
        null => "空值",                          // 常量模式
        _ => $"其他类型:{obj.GetType().Name}"   // 丢弃模式(默认情况)
    };
    // _: 丢弃模式,匹配任何其他情况

    Console.WriteLine($"  describe(42) = {describe(42)}");
    Console.WriteLine($"  describe(-5) = {describe(-5)}");
    Console.WriteLine($"  describe(0) = {describe(0)}");
    Console.WriteLine($"  describe(\"Hello\") = {describe("Hello")}");
    Console.WriteLine($"  describe(3.14) = {describe(3.14)}");
}
#endregion

8.4输出

=== 8. 高级主题 ===

8.1 递归 Lambda:
  阶乘 5! = 120
  阶乘 10! = 3628800

8.2 Lambda 作为返回值:
  doubleIt(5) = 10
  tripleIt(5) = 15

8.3 柯里化:
  柯里化加法:5 + 3 + 2 = 10
  直接调用:10

8.4 组合函数:
  addThenMultiply(3) = 8
  composed(3) = 64

8.5 记忆化:
  斐波那契数列:
    F(1) = 1
    F(2) = 1
    F(3) = 2
    F(4) = 3
    F(5) = 5
    F(6) = 8
    F(7) = 13
    F(8) = 21
    F(9) = 34
    F(10) = 55

8.6 模式匹配:
  describe(42) = 正整数:42
  describe(-5) = 负整数:-5
  describe(0) = 零:0
  describe("Hello") = 字符串:'Hello'
  describe(3.14) = 其他类型:Double

九.实际应用示例

9.1核心概念

展示Lambda在具体设计模式和框架中的应用。

9.2详细说明与示例

a.配置系统(流畅调用API)

示例config.Configure(options => { options.LogLevel = “Debug”; … });

Lambda特性:Lambda作为委托参数(回调/配置器)。

特性解析

Configure方法接受一个 Action<AppConfig.Options>类型的委托作为参数。调用方通过传入一个Lambda表达式 options => { ... }来具体实现这个委托。
这个Lambda充当了一个配置器的角色,它接收一个配置对象 options作为输入,并在其语句块中对其进行修改。这种方式将配置逻辑内联、即时地定义在调用处,代码意图非常清晰,无需预先定义额外的方法,形成了流畅的API调用风格。

b.验证器(规则引擎)

示例validator.AddRule(u => !string.IsNullOrEmpty(u.Name), “姓名不能为空”);

所用Lambda特性:Lambda作为谓词(判断条件)​ 与 组合使用(多规则集合)

特性解析

每个验证规则都是一个 Func<User, bool>类型的Lambda,例如u=>!string.IsNullOrEmpty(u.Name)。这是一个谓词,它接受一个用户对象,返回一个布尔值表示该规则是否通过。
Validator<T>类内部维护了一个这样的Lambda委托列表。通过 AddRule方法,可以灵活地添加任意数量的验证规则,每个规则都是一个独立的Lambda。这体现了Lambda的轻量级和可组合性,使得验证规则可以像数据一样被动态管理和执行。

c.中间件管道(责任链模式)

示例pipeline.Use(async (context, next) => { … await next(); … });

Lambda特性:异步Lambda​ 与 Lambda捕获外部变量(闭包)

特性解析

异步Lambda:每个中间件都是一个 Func<PipelineContext, Func<Task>, Task>类型的异步Lambda。Lambda内部使用了 async/await关键字(如 await next();)来非阻塞地调用管道中的下一个中间件,并可以在调用前后执行逻辑。
闭包:每个Lambda都捕获了其外部的 PipelineContext context和 Func<Task> next参数。这使得它们能够操作共享的上下文 (context.Data += "->1") 并控制流程的传递 (await next())。通过将多个这样的Lambda按顺序添加到管道中,就构建了一条可扩展的请求处理链。

执行开始
    │
    ▼
[Middleware 1] 开始
    │
    ▼
context.Data = "请求->1"  (修改数据)
    │
    ▼
await next() ──────────────┐
    │                      │
    │                      ▼
    │              [Middleware 2] 开始
    │                      │
    │                      ▼
    │              context.Data = "请求->1->2"
    │                      │
    │                      ▼
    │              await next() ───────┐
    │                      │           │
    │                      │           ▼
    │                      │   [Middleware 3] 开始
    │                      │           │
    │                      │           ▼
    │                      │   context.Data = "请求->1->2->3"
    │                      │           │
    │                      │           ▼
    │                      │   await next()  (无下一个中间件)
    │                      │           │
    │                      │           ▼
    │                      │   [Middleware 3] 结束
    │                      │           │
    │                      │           │
    │                      ◄───────────┘
    │                      │
    │                      ▼
    │              [Middleware 2] 结束
    │                      │
    │                      │
    ◄──────────────────────┘
    │
    ▼
[Middleware 1] 结束
    │
    ▼
执行完成
最终数据:"请求->1->2->3"

d.策略模式

示例calculator.AddStrategy(“VIP”, amount => amount * 0.8m);

Lambda特性:Lambda作为轻量级的策略实现

特性解析

每个折扣策略(如VIP折扣、学生折扣)都被定义为一个 Func<decimal, decimal>类型的Lambda,例如 amount => amount * 0.8m。这个Lambda完整封装了该策略的算法逻辑。
DiscountCalculator类内部使用一个字典来存储策略名称与对应Lambda委托的映射。当需要计算折扣时,根据策略名从字典中取出对应的Lambda并执行。这避免了为每个策略创建单独的类,利用Lambda的简洁语法和第一类函数的特性,将策略直接表示为可执行的代码块,极大地减少了样板代码。

9.3例程

#region 9. 实际应用示例

/// <summary>
/// 演示 Lambda 在实际开发中的应用场景
/// </summary>
static void DemonstratePracticalExamples()
{
    Console.WriteLine();
    Console.WriteLine("=== 9. 实际应用示例 ===");
    Console.WriteLine();

    // 9.1 配置系统(流畅调用API)
    Console.WriteLine("9.1 配置系统:");

    var config = new AppConfig();

    // 使用 Lambda 配置选项
    // options: 配置对象
    // { ... }: 语句块,设置属性
    config.Configure(options =>
    {
        options.LogLevel = "Debug";
        options.Timeout = TimeSpan.FromSeconds(30);
        options.Features = new List<string> { "Auth", "Caching", "Logging" };
    });

    config.PrintConfig();

    // 9.2 验证器(规则引擎)
    Console.WriteLine();
    Console.WriteLine("9.2 验证器:");

    var userValidator = new Validator<User>();

    // 添加验证规则 - 每个规则是一个 Lambda
    // u => !string.IsNullOrEmpty(u.Name): 验证姓名非空
    userValidator.AddRule(u => !string.IsNullOrEmpty(u.Name), "姓名不能为空");
    // u => u.Age >= 0 && u.Age <= 150: 验证年龄范围
    userValidator.AddRule(u => u.Age >= 0 && u.Age <= 150, "年龄必须在 0-150 之间");
    // u => u.Email?.Contains('@') ?? false: 验证邮箱格式
    // ?. : 空条件运算符,如果 u.Email 为 null 则返回 null
    // ??: 空合并运算符,如果左边为 null 则返回 false
    userValidator.AddRule(u => u.Email?.Contains('@') ?? false, "邮箱格式不正确");

    // 创建测试用户
    var testUser = new User
    {
        Name = "John",
        Age = 200,  // 无效年龄
        Email = "invalid-email"
    };

    // 执行验证
    var validationResult = userValidator.Validate(testUser);
    Console.WriteLine("  用户验证结果:");
    foreach (var error in validationResult.Errors)
    {
        Console.WriteLine($"    - {error}");
    }

    // 9.3 中间件管道(责任链模式)
    Console.WriteLine();
    Console.WriteLine("9.3 中间件管道:");

    var pipeline = new MiddlewarePipeline();

    // 添加中间件 1
    // (context, next): 中间件的两个参数
    // context: 管道上下文,携带请求数据
    // next: 下一个中间件的委托
    pipeline.Use(async (context, next) =>
    {
        Console.WriteLine("  [Middleware 1] 开始");
        context.Data += "->1";  // 处理数据
        await next();  // 调用下一个中间件
        Console.WriteLine("  [Middleware 1] 结束");
    });

    // 添加中间件 2
    pipeline.Use(async (context, next) =>
    {
        Console.WriteLine("  [Middleware 2] 开始");
        context.Data += "->2";
        await next();
        Console.WriteLine("  [Middleware 2] 结束");
    });

    // 添加中间件 3
    pipeline.Use(async (context, next) =>
    {
        Console.WriteLine("  [Middleware 3] 开始");
        context.Data += "->3";
        await next();
        Console.WriteLine("  [Middleware 3] 结束");
    });

    // 执行管道
    var context = new PipelineContext { Data = "请求" };
    pipeline.Execute(context).Wait();  // 同步等待
    Console.WriteLine($"  最终数据:{context.Data}");

    // 9.4 策略模式
    Console.WriteLine();
    Console.WriteLine("9.4 策略模式:");

    var calculator = new DiscountCalculator();

    // 添加折扣策略 - 每个策略是一个 Lambda
    // amount => amount * 0.8m: 8 折
    // decimal 字面量使用 m 后缀
    calculator.AddStrategy("VIP", amount => amount * 0.8m);

    // amount => amount * 0.9m: 9 折
    calculator.AddStrategy("Student", amount => amount * 0.9m);

    // amount => amount > 100 ? amount - 20 : amount * 0.8m
    // 三元运算符:满 100 减 20,否则 8 折
    calculator.AddStrategy("Double11", amount =>
        amount > 100 ? amount - 20 : amount * 0.8m);

    Console.WriteLine("  折扣计算:");
    Console.WriteLine($"  VIP 100 元 -> {calculator.Calculate("VIP", 100m):C}");
    Console.WriteLine($"  Student 100 元 -> {calculator.Calculate("Student", 100m):C}");
    Console.WriteLine($"  Double11 150 元 -> {calculator.Calculate("Double11", 150m):C}");
    Console.WriteLine($"  Double11 80 元 -> {calculator.Calculate("Double11", 80m):C}");
}
#endregion

9.4输出

=== 9. 实际应用示例 ===

9.1 配置系统:
  应用配置:
    日志级别:Debug
    超时时间:30秒
    功能列表:Auth, Caching, Logging

9.2 验证器:
  用户验证结果:
    - 年龄必须在 0-150 之间
    - 邮箱格式不正确

9.3 中间件管道:
  [Middleware 3] 开始
  [Middleware 2] 开始
  [Middleware 1] 开始
  [Middleware 1] 结束
  [Middleware 2] 结束
  [Middleware 3] 结束
  最终数据:请求->3->2->1

9.4 策略模式:
  折扣计算:
  VIP 100 元 -> ¥80.00
  Student 100 元 -> ¥90.00
  Double11 150 元 -> ¥130.00
  Double11 80 元 -> ¥64.00

十.程序主体

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Reflection;
using System.Diagnostics;
using System.ComponentModel;

#pragma warning disable IDE0039//抑制局部函数优于Lambda警告
#pragma warning disable IDE0063//抑制简化using警告
#pragma warning disable IDE0090//抑制简化new警告
#pragma warning disable IDE0028//抑制简化集合初始化警告
#pragma warning disable IDE0300//抑制简化数组初始化警告
#pragma warning disable IDE0350//抑制简化Lambda警告
#pragma warning disable IDE0290//抑制主构造函数警告

namespace CSharpLambdaCompleteDemo
{
    /// <summary>
    /// 主程序类 - 完整演示 C# Lambda 表达式的语法和高级应用
    /// Lambda 表达式是一种匿名函数,可用于创建委托或表达式树对象
    /// </summary>
    class Program
    {
        下面各个章节单独列举:
        1. 基本 Lambda 语法
        2. 委托与 Lambda
        3. 闭包与变量捕获
        4. LINQ 与 Lambda
        5. 表达式树 (Expression Trees)
        6. 事件与 Lambda
        7. 异步 Lambda
        8. 高级主题
        9. 实际应用示例

        /// <summary>
        /// 程序入口点(Main 方法)
        /// async Task: 异步 Main 方法(C# 7.1+)
        /// </summary>
        /// <param name="args">命令行参数</param>
        static async Task Main(string[] args)
        {
            Console.WriteLine("C# Lambda 表达式完整演示");
            Console.WriteLine("=============================");
            Console.WriteLine();

            // 依次执行各个演示模块
            DemonstrateBasicSyntax();
            DemonstrateDelegatesAndLambda();
            DemonstrateClosures();
            DemonstrateLINQAndLambda();
            DemonstrateExpressionTrees();
            DemonstrateEventsAndLambda();
            await DemonstrateAsyncLambda();  // 异步方法需要 await
            DemonstrateAdvancedTopics();
            DemonstratePracticalExamples();

            Console.WriteLine();
            Console.WriteLine("演示结束,按任意键退出...");
            Console.ReadKey();
        }
    }

    #region 辅助类定义

    /// <summary>
    /// 人员类(基础数据模型)
    /// </summary>
    class Person
    {
        /// <summary>
        /// 姓名属性
        /// string?: 可空引用类型(允许为 null)
        /// get; set;: 自动实现的属性
        /// </summary>
        public string? Name { get; set; }

        /// <summary>
        /// 年龄属性
        /// int: 值类型(不允许为 null)
        /// </summary>
        public int Age { get; set; }
    }

    /// <summary>
    /// 员工类(用于 LINQ 演示的数据模型)
    /// </summary>
    class Employee
    {
        /// <summary>
        /// 员工 ID(主键)
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string? Name { get; set; }

        /// <summary>
        /// 部门名称
        /// </summary>
        public string? Department { get; set; }

        /// <summary>
        /// 工资(double 类型)
        /// </summary>
        public double Salary { get; set; }

        /// <summary>
        /// 年龄
        /// </summary>
        public int Age { get; set; }
    }

    /// <summary>
    /// 项目类(用于演示 Join 操作)
    /// </summary>
    class Project
    {
        /// <summary>
        /// 项目 ID(主键)
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 项目名称
        /// </summary>
        public string? Name { get; set; }

        /// <summary>
        /// 负责人 ID(外键,关联 Employee.Id)
        /// </summary>
        public int LeaderId { get; set; }
    }

    /// <summary>
    /// 数据处理器类(用于演示事件处理)
    /// </summary>
    class DataProcessor
    {
        /// <summary>
        /// 数据接收事件
        /// event: 事件关键字(封装委托,只能+= 和-=)
        /// EventHandler<string>: 泛型事件处理器委托
        /// ?: 可空引用类型
        /// </summary>
        public event EventHandler<string>? DataReceived;

        /// <summary>
        /// 数据处理完成事件
        /// EventHandler<ProcessingEventArgs>: 携带自定义事件参数
        /// </summary>
        public event EventHandler<ProcessingEventArgs>? DataProcessed;

        /// <summary>
        /// 进度变更事件
        /// EventHandler<int>: 携带 int 类型的进度值
        /// </summary>
        public event EventHandler<int>? ProgressChanged;

        /// <summary>
        /// 开始处理数据(触发一系列事件)
        /// </summary>
        /// <param name="data">要处理的数据</param>
        public void StartProcessing(string data)
        {
            OnDataReceived(data);  // 触发数据接收事件

            // 模拟处理进度(0% 到 100%)
            for (int i = 0; i <= 100; i += 10)
            {
                OnProgressChanged(i);  // 触发进度事件
                System.Threading.Thread.Sleep(50);  // 模拟耗时
            }

            var result = $"处理结果:{data.ToUpper()}";
            OnDataProcessed(result);  // 触发处理完成事件
        }

        /// <summary>
        /// 处理单个数据(仅触发接收事件)
        /// </summary>
        /// <param name="data">数据</param>
        public void ProcessSingleData(string data)
        {
            OnDataReceived(data);
        }

        /// <summary>
        /// 触发数据接收事件(受保护的虚方法)
        /// virtual: 可被子类重写
        /// </summary>
        /// <param name="data">数据</param>
        protected virtual void OnDataReceived(string data)
        {
            // ?: 空条件运算符,如果 DataReceived 不为 null 才调用
            DataReceived?.Invoke(this, data);
        }

        /// <summary>
        /// 触发数据处理完成事件
        /// </summary>
        /// <param name="result">处理结果</param>
        protected virtual void OnDataProcessed(string result)
        {
            DataProcessed?.Invoke(this, new ProcessingEventArgs(result));
        }

        /// <summary>
        /// 触发进度变更事件
        /// </summary>
        /// <param name="progress">进度百分比(0-100)</param>
        protected virtual void OnProgressChanged(int progress)
        {
            ProgressChanged?.Invoke(this, progress);
        }
    }

    /// <summary>
    /// 处理事件参数类(携带处理结果信息)
    /// 继承自 EventArgs(事件参数的基类)
    /// </summary>
    class ProcessingEventArgs : EventArgs
    {
        /// <summary>
        /// 处理结果(只读属性)
        /// get;: 只有 getter,外部不可修改
        /// </summary>
        public string Result { get; }

        /// <summary>
        /// 构造函数(初始化事件参数)
        /// </summary>
        /// <param name="result">处理结果</param>
        public ProcessingEventArgs(string result)
        {
            Result = result;
        }
    }

    /// <summary>
    /// 传感器类(演示属性变更事件)
    /// </summary>
    class Sensor
    {
        private double _reading;  // 私有字段,存储实际值

        /// <summary>
        /// 传感器读数属性(带变更检测)
        /// get => _reading: 表达式-bodied getter
        /// set: setter,包含变更检测和事件触发
        /// </summary>
        public double Reading
        {
            get => _reading;  // 返回字段值
            set
            {
                // 检查变化是否超过阈值(避免微小变化触发事件)
                if (Math.Abs(_reading - value) > 0.1)
                {
                    var oldValue = _reading;  // 保存旧值
                    _reading = value;         // 更新字段
                    OnReadingChanged(oldValue, value);  // 触发事件
                }
            }
        }

        /// <summary>
        /// 读数变更事件
        /// </summary>
        public event EventHandler<ReadingChangedEventArgs>? ReadingChanged;

        /// <summary>
        /// 触发读数变更事件(受保护的虚方法)
        /// </summary>
        /// <param name="oldValue">旧值</param>
        /// <param name="newValue">新值</param>
        protected virtual void OnReadingChanged(double oldValue, double newValue)
        {
            ReadingChanged?.Invoke(this, new ReadingChangedEventArgs(oldValue, newValue));
        }
    }

    /// <summary>
    /// 读数变更事件参数类(携带读数变化的详细信息)
    /// </summary>
    class ReadingChangedEventArgs : EventArgs
    {
        /// <summary>
        /// 旧读数(只读)
        /// </summary>
        public double OldValue { get; }

        /// <summary>
        /// 新读数(只读)
        /// </summary>
        public double NewValue { get; }

        /// <summary>
        /// 变更时间(只读)
        /// </summary>
        public DateTime ChangeTime { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="oldValue">旧值</param>
        /// <param name="newValue">新值</param>
        public ReadingChangedEventArgs(double oldValue, double newValue)
        {
            OldValue = oldValue;
            NewValue = newValue;
            ChangeTime = DateTime.Now;  // 记录当前时间
        }
    }

    /// <summary>
    /// 异步处理器类(演示异步事件处理)
    /// </summary>
    class AsyncProcessor
    {
        /// <summary>
        /// 处理开始事件(异步版本)
        /// Func<object, string, Task>: 返回 Task 的委托(异步)
        /// object: sender 参数
        /// string: fileName 参数
        /// Task: 返回类型(异步操作)
        /// </summary>
        public event Func<object, string, Task>? ProcessingStarted;

        /// <summary>
        /// 处理完成事件(异步版本)
        /// </summary>
        public event Func<object, string, Task>? ProcessingCompleted;

        /// <summary>
        /// 异步处理文件
        /// async Task: 异步方法
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <returns>异步任务</returns>
        public async Task ProcessFileAsync(string fileName)
        {
            // 触发处理开始事件
            if (ProcessingStarted != null)
            {
                await ProcessingStarted.Invoke(this, fileName);
            }

            await Task.Delay(200);  // 模拟处理过程

            var result = $"{fileName} 处理完成,大小:1024KB";

            // 触发处理完成事件
            if (ProcessingCompleted != null)
            {
                await ProcessingCompleted.Invoke(this, result);
            }
        }
    }

    /// <summary>
    /// 应用配置类(演示使用 Lambda 进行配置)
    /// </summary>
    class AppConfig
    {
        /// <summary>
        /// 配置选项类(嵌套类)
        /// </summary>
        public class Options
        {
            /// <summary>
            /// 日志级别属性
            /// </summary>
            public string LogLevel { get; set; } = "Info";

            /// <summary>
            /// 超时时间属性
            /// TimeSpan: 时间跨度类型
            /// </summary>
            public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10);

            /// <summary>
            /// 功能列表属性
            /// List<string>: 字符串列表
            /// </summary>
            public List<string> Features { get; set; } = new List<string>();
        }

        private readonly Options _options = new Options();  // 配置对象

        /// <summary>
        /// 配置方法(接受 Action 委托)
        /// Action<Options>: 接受 Options 参数,无返回值
        /// configure?: 可空委托
        /// </summary>
        /// <param name="configure">配置委托(Lambda)</param>
        public void Configure(Action<Options> configure)
        {
            configure?.Invoke(_options);  // 调用配置 Lambda
        }

        /// <summary>
        /// 打印配置信息到控制台
        /// </summary>
        public void PrintConfig()
        {
            Console.WriteLine("  应用配置:");
            Console.WriteLine($"    日志级别:{_options.LogLevel}");
            Console.WriteLine($"    超时时间:{_options.Timeout.TotalSeconds}秒");
            Console.WriteLine($"    功能列表:{string.Join(", ", _options.Features)}");
        }
    }

    /// <summary>
    /// 用户类(用于验证器演示)
    /// </summary>
    class User
    {
        /// <summary>
        /// 姓名
        /// </summary>
        public string? Name { get; set; }

        /// <summary>
        /// 年龄
        /// </summary>
        public int Age { get; set; }

        /// <summary>
        /// 邮箱地址
        /// </summary>
        public string? Email { get; set; }
    }

    /// <summary>
    /// 验证结果类(封装验证结果和错误信息)
    /// </summary>
    class ValidationResult
    {
        /// <summary>
        /// 是否验证通过(计算属性)
        /// => Errors.Count == 0: 表达式-bodied 属性
        /// </summary>
        public bool IsValid => Errors.Count == 0;

        /// <summary>
        /// 错误信息列表
        /// { get; } = ...: 只读属性,初始化时赋值
        /// </summary>
        public List<string> Errors { get; } = new List<string>();
    }

    /// <summary>
    /// 泛型验证器类(使用 Lambda 定义验证规则)
    /// </summary>
    /// <typeparam name="T">要验证的类型</typeparam>
    class Validator<T>
    {
        // 规则列表:每个规则是一个 Func<T, bool> 委托
        private readonly List<Func<T, bool>> _rules = new List<Func<T, bool>>();

        // 错误消息列表(与规则一一对应)
        private readonly List<string> _errorMessages = new List<string>();

        /// <summary>
        /// 添加验证规则
        /// </summary>
        /// <param name="rule">验证规则(Lambda 表达式)</param>
        /// <param name="errorMessage">错误消息</param>
        public void AddRule(Func<T, bool> rule, string errorMessage)
        {
            _rules.Add(rule);           // 添加规则委托
            _errorMessages.Add(errorMessage);  // 添加对应的错误消息
        }

        /// <summary>
        /// 执行验证
        /// </summary>
        /// <param name="item">要验证的对象</param>
        /// <returns>验证结果对象</returns>
        public ValidationResult Validate(T item)
        {
            var result = new ValidationResult();  // 创建结果对象

            // 遍历所有规则
            for (int i = 0; i < _rules.Count; i++)
            {
                // _rules[i](item): 调用第 i 个规则委托
                // 如果不满足规则(返回 false),添加错误消息
                if (!_rules[i](item))
                {
                    result.Errors.Add(_errorMessages[i]);
                }
            }

            return result;
        }
    }

    /// <summary>
    /// 管道上下文类(在中间件之间传递数据)
    /// </summary>
    class PipelineContext
    {
        /// <summary>
        /// 数据属性(在中间件中传递和修改)
        /// </summary>
        public string? Data { get; set; }
    }

    /// <summary>
    /// 请求委托(定义中间件的签名)
    /// </summary>
    /// <param name="context">管道上下文</param>
    /// <returns>异步任务</returns>
    delegate Task RequestDelegate(PipelineContext context);

    /// <summary>
    /// 中间件管道类(实现责任链模式)
    /// </summary>
    class MiddlewarePipeline
    {
        private RequestDelegate? _pipeline;  // 管道委托(存储中间件链)

        /// <summary>
        /// 添加中间件到管道
        /// </summary>
        /// <param name="middleware">中间件委托</param>
        public void Use(Func<PipelineContext, Func<Task>, Task> middleware)
        {
            // 如果_pipeline 为 null,使用默认的空操作
            var next = _pipeline ?? (context => Task.CompletedTask);
            // ??: 空合并运算符,如果左边为 null 则使用右边

            // 构建新的管道:当前中间件包装下一个中间件
            _pipeline = context => middleware(context, () => next(context));
            // context => ...: 新的 RequestDelegate
            // middleware(context, () => next(context)): 调用中间件
            // () => next(context): 下一个中间件的包装
        }

        /// <summary>
        /// 执行管道(运行所有中间件)
        /// </summary>
        /// <param name="context">管道上下文</param>
        /// <returns>异步任务</returns>
        public async Task Execute(PipelineContext context)
        {
            if (_pipeline != null)
            {
                await _pipeline(context);  // 执行管道
            }
        }
    }

    /// <summary>
    /// 折扣计算器类(实现策略模式)
    /// </summary>
    class DiscountCalculator
    {
        // 策略字典:键是策略名称,值是折扣计算委托
        private readonly Dictionary<string, Func<decimal, decimal>> _strategies =
            new Dictionary<string, Func<decimal, decimal>>();

        /// <summary>
        /// 添加折扣策略
        /// </summary>
        /// <param name="name">策略名称</param>
        /// <param name="strategy">折扣计算委托(Lambda)</param>
        public void AddStrategy(string name, Func<decimal, decimal> strategy)
        {
            _strategies[name] = strategy;  // 添加到字典
        }

        /// <summary>
        /// 计算折扣后价格
        /// </summary>
        /// <param name="strategyName">策略名称</param>
        /// <param name="amount">原价金额</param>
        /// <returns>折扣后价格</returns>
        public decimal Calculate(string strategyName, decimal amount)
        {
            // TryGetValue: 尝试获取策略
            if (_strategies.TryGetValue(strategyName, out var strategy))
            {
                return strategy(amount);  // 应用策略(调用 Lambda)
            }

            return amount;  // 默认无折扣
        }
    }

    #endregion

    #region 扩展方法

    /// <summary>
    /// Lambda 扩展方法类(静态工具类)
    /// static: 静态类,不能被实例化
    /// </summary>
    static class LambdaExtensions
    {
        /// <summary>
        /// 获取前 N 个元素(按指定键降序排列)
        /// 扩展方法:使用 this 关键字
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <param name="source">源集合(this 参数)</param>
        /// <param name="keySelector">键选择器 Lambda</param>
        /// <param name="n">要获取的数量</param>
        /// <returns>前 N 个元素</returns>
        public static IEnumerable<T> TopN<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, int n)
        {
            // source: 被扩展的集合(this 参数)
            // keySelector: Lambda 表达式,用于提取排序键
            // OrderByDescending: 按降序排序
            // Take: 取前 n 个元素
            return source.OrderByDescending(keySelector).Take(n);
        }

        /// <summary>
        /// 组合两个函数(函数式编程中的函数组合)
        /// 数学定义:(g ∘ f)(x) = g(f(x))
        /// </summary>
        /// <typeparam name="T">输入和输出类型</typeparam>
        /// <param name="func1">第一个函数 f</param>
        /// <param name="func2">第二个函数 g</param>
        /// <returns>组合后的函数</returns>
        public static Func<T, T> Compose<T>(this Func<T, T> func1, Func<T, T> func2)
        {
            // x => func2(func1(x)): 组合函数
            // 先执行 func1,再将结果传给 func2
            return x => func2(func1(x));
        }
    }

    #endregion
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐