C# Lambda 表达式:从基础用法到集合操作实战

0 阅读8分钟

Lambda 表达式是 C# 函数式编程的核心,尤其在 Entity Framework (EF) 数据查询、集合操作中是必备技能。本文基于我的学习笔记全面优化,补充无返回值/有返回值完整实例、新手避坑指南,帮你彻底掌握 Lambda 用法。

一、Lambda 核心概念与简化规则

Lambda 是匿名函数的简写形式,核心语法:(参数) => 表达式/语句块=> 读作“goes to”(输入参数→输出结果)。

先修正新手高频错误(类型匹配)

原始笔记中典型错误:委托类型与参数类型不匹配,编译器直接报错:

// ❌ 错误:Action<string> 要求参数是string,但匿名委托参数是int
Action<string> a1 = delegate(int i) { Console.WriteLine(i); };

// ✅ 正确:Action<int> 匹配 int 类型参数(核心:委托类型 ≡ 参数类型)
Action<int> a1 = delegate(int i) { Console.WriteLine(i); };

image

Lambda 简化过程(以“打印整数”为例)

以下每一步代码均可直接运行,逐步体会“从繁到简”的核心逻辑:

简化阶段代码示例核心简化点
1. 传统匿名委托Action<int> a1 = delegate(int i) { Console.WriteLine(i); };无(最基础写法,无简化)
2. 替换为 LambdaAction<int> a2 = (int i) => { Console.WriteLine(i); };delegate 关键字 → => 符号
3. 省略参数类型Action<int> a3 = (i) => { Console.WriteLine(i); };编译器根据委托类型自动推断参数类型
4. 省略参数括号(单参数)Action<int> a4 = i => { Console.WriteLine(i); };单个参数时,括号可省略(多参数必须保留)
5. 省略大括号(单行语句)Action<int> a5 = i => Console.WriteLine(i);语句体仅一行时,大括号可省略

无返回值 vs 有返回值 Lambda 核心规则

类型委托基类核心规则示例
无返回值Action<T>单行可省 {},无 returni => Console.WriteLine(i)
有返回值Func<T,TResult>单行可省 {} + return,多行必须手动 return(i,j) => i+j(单行)
(i,j) => { var s=i+j; return s; }(多行)

带返回值的 Lambda 简化(关键规则)

如果委托有返回值(如 Func),且方法体只有一行代码且是返回值,可省略 {}return

// 传统匿名委托(带返回值)
Func<int, int, string> f1 = delegate (int i, int j)
{
    return "结果是" + (i + j);
};

// Lambda 极简写法(省略 {} 和 return)
Func<int, int, string> f2 = (i, j) => "结果是" + (i + j);

// 调用f1(匿名委托)
Console.WriteLine(f1(4,5)); // 输出:f1结果是:8

// 调用f2(Lambda表达式)
Console.WriteLine(f2(3, 5)); // 输出:f2结果是:8

image


二、核心实例:无返回值/有返回值 Lambda 完整演示

1. 无返回值 Lambda(Action 委托)

核心用于“执行操作但不返回结果”(打印、修改数据、遍历),覆盖单参数/多参数/无参数场景:

namespace _03_无返回值_Lambda_Action_委托_
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 1. 单参数无返回值(最简写法)
            Action<int> printNum = num => Console.WriteLine($"数字:{num}");
            printNum(100);

            // 2. 多参数无返回值(拼接信息)
            Action<string, int> printUser = (name, age) => Console.WriteLine($"姓名:{name},年龄:{age}");
            printUser("张三", 25); 

            // 3. 无参数无返回值(固定逻辑)
            Action printHello = () => Console.WriteLine("Hello Lambda!");
            printHello();

            Console.ReadLine();
        }
    }
}

image

2. 有返回值 Lambda(Func 委托)

核心用于“执行逻辑并返回结果”(计算、筛选、转换),覆盖单行/多行场景:

namespace _04_有返回值_Lambda_Func_委托_
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 1. 单行简化(自动返回,省略 return)
            Func<int, int> getSquare = num => num * num;
            Console.WriteLine($"5的平方:{getSquare(5)}");

            // 2. 多行语句(必须手动 return)
            Func<int, string> checkAdult = age =>
            {
                Console.WriteLine($"检查年龄:{age}"); // 中间操作
                return age >= 18 ? "成年" : "未成年";
            };
            Console.WriteLine(checkAdult(20)); 

            Console.ReadLine();
        }
    }
}

image


三、实战练习(带完整代码+运行结果+新手解析)

练习一:Lambda 基础简化(验证简化规则)

目标:逐行验证 Lambda 从匿名委托到极简写法的过程
完整代码

using System;

class Program
{
    static void Main(string[] args)
    {
        // 1. 传统匿名委托
        Action<int> a1 = delegate(int i) { Console.WriteLine($"版本1:{i}"); };
        a1(10);

        // 2. 基础 Lambda(替换 delegate 为 =>)
        Action<int> a2 = (int i) => { Console.WriteLine($"版本2:{i}"); };
        a2(20);

        // 3. 省略参数类型(编译器自动推断)
        Action<int> a3 = (i) => { Console.WriteLine($"版本3:{i}"); };
        a3(30);

        // 4. 省略括号+大括号(单参数+单行极简)
        Action<int> a4 = i => Console.WriteLine($"版本4:{i}");
        a4(40);

        Console.ReadLine();
    }
}

运行结果

版本1:10
版本2:20
版本3:30
版本4:40

image 新手解析:每一步简化都不改变逻辑,仅减少冗余语法,编译器会自动补全推断的信息。

练习二:Select 处理整数集合(生成新集合)

目标:用 Select 转换集合元素(核心:“一对一”处理)
完整代码

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        List<int> list1 = new List<int> { 1, 2, 3, 8, 16, 99 };
        
        // Select:对每个元素拼接"你好",生成新的字符串集合
        IEnumerable<string> data = list1.Select(i => i + "你好");
        
        // 遍历输出新集合
        foreach (var item in data)
        {
            Console.WriteLine(item);
        }
        Console.ReadLine();
    }
}

运行结果

1你好
2你好
3你好
8你好
16你好
99你好

image

新手解析Select 是“转换器”,原集合 list1 不变,新集合 data 是转换后的结果。

练习三:Where 过滤整数集合(筛选元素)

目标:用 Where 按条件筛选元素(核心:Lambda 返回 bool)
完整代码

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        List<int> list1 = new List<int> { 1, 2, 3, 8, 16, 99 };
        
        // Where:筛选大于10的元素(Lambda 返回 true 则保留)
        IEnumerable<int> data = list1.Where(i => i > 10);
        
        Console.WriteLine("大于10的元素:");
        foreach (var item in data)
        {
            Console.WriteLine(item);
        }
        Console.ReadLine();
    }
}

运行结果

大于10的元素:
16,99

image

新手解析Where 的 Lambda 必须返回 bool 类型,true 保留元素,false 过滤掉。

练习四:对象集合求和(Sum 方法)

目标:计算对象集合中指定属性的总和
完整代码

internal class Program
{
    static void Main(string[] args)
    {
        Person[] p = new Person[]
        {
            new Person { Name="chen", Age=12 },
            new Person { Name="chen2", Age=24 },
            new Person { Name="chen3", Age=12 }
        };

        // Sum:Lambda 指定“要累加的属性(Age)”
        int totalAge = p.Sum(i => i.Age);

        // 类型转换:数组 ↔ 列表(EF中常用)
        List<Person> ps = p.ToList();
        Person[] ps4 = p.ToArray();

        Console.WriteLine("年龄总和:" + totalAge); // 12+24+12=48
        Console.ReadKey();
    }

    class Person
    {
        public string Name { get; set; } // 姓名
        public int Age { get; set; }     // 年龄
    }
}

运行结果

年龄总和:48

image

新手解析Sum 的 Lambda 需返回数值类型(int/double),指定“要求和的属性”即可自动累加。

练习五:对象集合综合操作(OrderBy/FirstOrDefault)

目标:组合多个扩展方法处理对象集合(EF 高频场景)
完整代码

internal class Program
{
    static void Main(string[] args)
    {
        Person[] p = new Person[]
        {
            new Person { Name="chen", Age=12 },
            new Person { Name="chen2", Age=24 },
            new Person { Name="chen3", Age=12 },
            new Person { Name="chen4", Age=30 }
        };

        // 1. 按年龄升序排序(降序用 OrderByDescending)
        var sorted = p.OrderBy(i => i.Age);
        Console.WriteLine("按年龄升序:");
        foreach (var item in sorted)
        {
            Console.WriteLine($"{item.Name} - {item.Age}岁");
        }

        // 2. 获取第一个年龄>20的人(无则返回null,避免异常)
        var firstAdult = p.FirstOrDefault(i => i.Age > 20);
        Console.WriteLine("\n第一个成年人:" + firstAdult?.Name);

        // 3. 获取年龄最大值(对象集合需指定属性)
        var maxAge = p.Max(i => i.Age);
        Console.WriteLine("最大年龄:" + maxAge);

        Console.ReadKey();
    }
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

运行结果

按年龄升序:
chen - 12岁
chen3 - 12岁
chen2 - 24岁
chen4 - 30岁

第一个成年人:chen2
最大年龄:30

image

新手解析:多个扩展方法可链式调用(如 p.Where(...).OrderBy(...).FirstOrDefault()),是 EF 查询的核心写法。


四、集合常用扩展方法(Lambda 高频用法·新手速查)

整理 EF/日常开发中最常用的扩展方法,附 Lambda 示例和避坑提示:

方法核心作用Lambda 示例新手避坑提示
Where过滤元素list.Where(i => i > 10)返回 IEnumerable,延迟执行(遍历才生效)
Select转换元素list.Select(i => i * 2)生成新集合,原集合完全不变
Max/Min最大/最小值p.Max(i => i.Age)空集合调用会抛异常,建议先判空
OrderBy/OrderByDescending升序/降序排序p.OrderBy(i => i.Age)多字段排序用 ThenBy
First获取第一个匹配元素list.First(i => i > 5)无匹配元素 → 抛异常(新手慎用)
FirstOrDefault获取第一个匹配元素list.FirstOrDefault(i => i > 5)无匹配 → 返回默认值,推荐使用
Single获取唯一匹配元素list.Single(i => i == 10)0个/多个匹配 → 抛异常
SingleOrDefault获取唯一匹配元素list.SingleOrDefault(i => i == 10)多个匹配 → 抛异常;0个 → 返回默认值
ToList/ToArray类型转换p.ToList() / p.ToArray()立即执行,EF 中需加 ToList() 才会执行查询

五、新手避坑指南(Lambda 高频错误)

  1. 委托类型不匹配Action<string> 不能接收 int 参数;
  2. 多行有返回值未加 return
    // ❌ 错误:多行必须手动 return
    Func<int, int> add = (a) => { a + 1; };
    // ✅ 正确
    Func<int, int> add = (a) => { return a + 1; };
    
  3. EF 中使用自定义方法:EF 无法解析自定义方法为 SQL,只能用内置方法;
  4. First/Single 空值异常:优先使用 FirstOrDefault/SingleOrDefault 避免报错。

总结

  1. Lambda 核心规则:单参数可省括号,单行有返回值可省 {}return,编译器自动推断参数类型;
  2. 核心场景:无返回值(Action)用于“执行操作”,有返回值(Func)用于“计算/查询”;
  3. EF 关键要点:Lambda 会被解析为 SQL,需使用 EF 支持的方法,加 ToList() 等方法才执行查询;
  4. 避坑核心:委托类型匹配、多行有返回值加 return、优先用 FirstOrDefault 避免异常。

掌握这些规则和示例,你就能在 C# 集合操作、EF 数据查询中灵活使用 Lambda,大幅简化代码并提升开发效率!


👋 关注我!持续分享 C# 实战技巧、代码示例 & 技术干货

  • 获取示例代码,轻松上手!

  • 私信输入数字: 9qfu19

  • 获取代码下载链接

    image