LINQ (语言集成查询) 是 C# 中的一组功能,它允许你使用统一的语法来查询不同的数据源(如内存集合、数据库、XML 等)。
它的核心优势在于:
为了演示,我们先定义一个简单的 `Student` 类和一些测试数据。
using System; using System.Collections.Generic; using System.Linq; public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string ClassName { get; set; } } // 模拟数据源 var students = new List<Student> { new Student { Id = 1, Name = "Alice", Age = 22, ClassName = "A" }, new Student { Id = 2, Name = "Bob", Age = 19, ClassName = "B" }, new Student { Id = 3, Name = "Charlie", Age = 24, ClassName = "A" }, new Student { Id = 4, Name = "David", Age = 20, ClassName = "B" }, new Student { Id = 5, Name = "Eve", Age = 22, ClassName = "A" } };
LINQ 有两种写法,它们在编译后是等价的。
看起来像 SQL,适合复杂的连接(Join)和分组操作。
// 查找所有年龄大于 20 岁的学生 var query = from s in students where s.Age > 20 select s;
使用 Lambda 表达式,是现代 C# 开发中最常用的方式,支持所有 LINQ 操作符。
// 查找所有年龄大于 20 岁的学生 var query = students.Where(s => s.Age > 20);
以下示例主要使用方法语法。
// 找出班级是 "A" 的学生 var classAStudents = students.Where(s => s.ClassName == "A");
用于转换数据,例如只取某一列,或者构造新的对象。
// 只获取所有学生的姓名 (返回 List<string>) var names = students.Select(s => s.Name); // 构造匿名对象 (只包含 ID 和 姓名) var simpleList = students.Select(s => new { s.Id, s.Name });
// 按年龄升序排序 var sortedByAge = students.OrderBy(s => s.Age); // 按年龄降序,如果年龄相同则按名字升序 var sortedComplex = students.OrderByDescending(s => s.Age) .ThenBy(s => s.Name);
常用于 Web 开发中的分页功能。
// 跳过前 2 个,取接下来的 2 个 (获取第 3、4 名学生) var page2 = students.Skip(2).Take(2);
用于计算统计数据。
int count = students.Count(); // 总数 int maxAge = students.Max(s => s.Age); // 最大年龄 double avgAge = students.Average(s => s.Age); // 平均年龄 int sumAge = students.Sum(s => s.Age); // 年龄总和
获取单个元素,注意处理空值情况。
// 获取第一个元素,如果没有则抛出异常 var first = students.First(s => s.Age > 20); // 获取第一个元素,如果没有则返回 null (推荐) var firstSafe = students.FirstOrDefault(s => s.Age > 100); // 检查是否包含满足条件的元素 (返回 bool) bool hasUnderage = students.Any(s => s.Age < 18); // 检查是否所有元素都满足条件 (返回 bool) bool allAdults = students.All(s => s.Age >= 18);
将数据按某个键归类。
// 按班级分组 var grouped = students.GroupBy(s => s.ClassName); foreach (var group in grouped) { Console.WriteLine($"班级: {group.Key}"); // Key 是 ClassName foreach (var student in group) { Console.WriteLine($" - {student.Name}"); } }
var list1 = new List<int> { 1, 2, 3 }; var list2 = new List<int> { 3, 4, 5 }; var union = list1.Union(list2); // 并集: 1, 2, 3, 4, 5 var intersect = list1.Intersect(list2); // 交集: 3 var except = list1.Except(list2); // 差集 (list1 - list2): 1, 2 var distinct = list1.Concat(list1).Distinct(); // 去重
这是 LINQ 中最重要的概念之一。
// 1. 定义查询 (此时还没运行) var query = students.Where(s => s.Age < 20); // 2. 修改数据源 (注意:我们在定义查询之后修改了数据) students.Add(new Student { Name = "NewKid", Age = 15 }); // 3. 执行查询 (foreach 或 ToList) // 结果会包含 "NewKid",因为查询是在这一行才真正执行的! var result = query.ToList();
最佳实践:
| 操作类型 | 常用方法 |
| 筛选 | Where, OfType |
| 投影 | Select, SelectMany |
| 排序 | OrderBy, OrderByDescending, ThenBy |
| 聚合 | Count, Sum, Min, Max, Average |
| 量词 | Any, All, Contains |
| 分区 | Skip, Take |
| 转换 | ToList, ToArray, ToDictionary |