C# LINQ 所有方法详解 + 使用场景(标准查询运算符,分两类:查询语法/方法语法)

发布时间:2026/7/18 16:35:43
C# LINQ 所有方法详解 + 使用场景(标准查询运算符,分两类:查询语法/方法语法) LINQ 分为延迟执行惰性和立即执行求值两大类还有聚合、元素、生成、集合修改方法全部附代码示例与适用场景。 底层基于IEnumerableT/IQueryableTEF 数据库查询优先用 IQueryable减少内存加载。一、筛选类延迟执行过滤数据1. Where 条件过滤作用按布尔条件筛选元素场景数据过滤、多条件筛选、数据库条件查询var list new Listint {1,2,3,4,5}; // 筛选大于3 var res list.Where(x x 3); // 4,5 // 带索引重载筛选偶数且索引大于1 var res2 list.Where((x,idx) x%20 idx1);EF 场景db.Users.Where(u u.Age 18 u.Status 1)2. OfType 按类型过滤作用集合中只取出指定类型元素自动忽略不匹配类型场景object 混合集合、控件集合、多态集合筛选IList objects new ArrayList { 1, abc, 2, def }; var strs objects.OfTypestring(); // abc,def二、投影/转换类延迟执行映射字段/对象1. Select 单对象投影映射作用转换每一个元素支持字段提取、对象重组、计算场景DTO 转换、只取需要字段、字段计算var users new ListUser(); // 只取姓名 var names users.Select(u u.Name); // 匿名类 var dto users.Select(u new {u.Id, u.Name, Age u.Birth.Year}); // 带索引 var indexed users.Select((u,i) new {Indexi, u.Name});2. SelectMany 集合扁平化一对多展开作用把集合内嵌套集合展开合并成一维序列场景一对多关系、嵌套列表展开、子集合遍历// 班级-学生 一对多 var classes new ListClass(); // 取出所有学生扁平化 var allStudents classes.SelectMany(c c.Students); // 同时保留父对象 var classStudent classes.SelectMany(c c.Students, (cls,stu)new {cls.Name, stu.Name});三、排序类延迟执行排序1. OrderBy / OrderByDescending 单字段升序/降序场景单一条件排序var asc users.OrderBy(u u.Age); // 年龄升序 var desc users.OrderByDescending(u u.CreateTime); // 创建时间倒序2. ThenBy / ThenByDescending 多字段次级排序作用主排序相同后次要条件排序必须跟在 OrderBy 后场景多维度复合排序// 先按年龄升序同龄按分数降序 var sort users.OrderBy(uu.Age).ThenByDescending(uu.Score);四、分区截取类延迟执行取部分数据1. Take(n) 取前 N 条场景分页首页、TopN 数据、限制返回条数var top3 list.Take(3); // 前3个2. TakeWhile 满足条件就持续取遇到不满足立刻停止场景连续符合条件数据截取var nums new Listint{1,2,4,1,5}; var take nums.TakeWhile(xx3); // 1,2到4停止3. Skip(n) 跳过前 N 条场景分页Skip((page-1)*size).Take(size)var page2 list.Skip(2).Take(3); // 跳过2条取3条4. SkipWhile 跳过满足条件元素直到不满足开始取值var skip nums.SkipWhile(xx3); // 4,1,5五、集合去重/对比延迟执行1. Distinct 去重场景获取不重复数据、枚举唯一值var arr new int[]{1,1,2,2,3}; var unique arr.Distinct(); // 1,2,3 // 自定义比较器复杂对象去重 var userDistinct users.Distinct(new UserNameComparer());2. Except 差集A有B没有的元素场景对比两个集合找出差异数据var a new Listint{1,2,3}; var b new Listint{3,4,5}; var diff a.Except(b); // 1,23. Intersect 交集两者都存在的元素场景共同数据筛选、权限交集匹配var same a.Intersect(b); // 34. Union 并集自动去重场景合并两个集合去除重复var all a.Union(b); // 1,2,3,4,55. Concat 简单拼接不去重场景单纯合并允许重复var concat a.Concat(b); // 1,2,3,3,4,5六、元素获取方法立即执行返回单个元素无匹配抛异常1. First() / FirstOrDefault()First()取第一个元素空集合抛异常FirstOrDefault()无数据返回类型默认值null/0 场景查询单条数据、第一条匹配记录var first users.Where(uu.Id1).FirstOrDefault();2. Last() / LastOrDefault()取序列最后一条数据库 IQueryable 慎用全查再取尾3. Single() / SingleOrDefault()Single只能有一条匹配多/无都报错 SingleOrDefault匹配0条返回默认多条报错 场景唯一主键查询Id主键确保只有一条数据var user db.Users.SingleOrDefault(uu.Id 1001);4. ElementAt(index) / ElementAtOrDefault(index)按索引取元素越界抛异常 / 返回默认 场景已知下标取值七、聚合函数立即执行返回数值1. Count() 统计总数无参数全部数量带条件Count(xx0)统计符合条件数量 场景分页总条数、条件计数int total users.Count(u u.Age 18);2. LongCount() 返回 long 类型计数超大集合3. Sum 求和数字集合求和支持投影Sum(xx.Score)int totalScore users.Sum(u u.Score);4. Min / Max 最小/最大值int maxAge users.Max(u u.Age); int minScore users.Min(u u.Score);5. Average 平均值仅数值类型可用double avgAge users.Average(u u.Age);6. Aggregate 自定义聚合万能累加器场景复杂合并、字符串拼接、自定义运算var nums new Listint{1,2,3,4}; // 累加 1234 int sum nums.Aggregate((acc,cur)acccur); // 带初始值拼接字符串 string str nums.Aggregate(0, (s,x)sx);八、判断存在性立即执行返回 bool1. Any() 是否存在至少一条数据无参数集合不为空带条件是否有满足条件元素推荐优先用 Any 判断存在性能优于 Count0bool hasAdult users.Any(u u.Age 18);2. All() 全部元素都满足条件场景批量校验数据合规性bool allPass users.All(u u.Score 60);3. Contains() 是否包含指定元素基础类型直接传值复杂对象需自定义比较器var list new Listint{1,2,3}; bool exist list.Contains(2);九、转换类型方法立即执行转为固定容器1. ToList() 转为 List最常用将 IEnumerable 加载到内存断开延迟执行 场景查询后多次遍历、修改集合、EF 查询落地内存var list db.Users.Where(uu.Age18).ToList();2. ToArray() 转为 T[] 数组3. ToDictionary(keySelector, valueSelector) 转字典场景主键快速索引Id映射实体var userDict users.ToDictionary(kk.Id, vv.Name);4. ToLookup() 多键一对多字典ILookup一个键对应多个值分组专用 场景按类别分组并快速索引var ageGroup users.ToLookup(u u.Age); var age20 ageGroup[20]; // 所有20岁用户5. AsEnumerable() / AsQueryable()AsQueryable()IEnumerable 转 IQueryable支持LINQ表达式树AsEnumerable()强制切换为内存LINQ数据库查询中局部处理 场景EF中部分逻辑无法转SQL强制内存计算十、分组方法 GroupBy延迟执行GroupBy 分组聚合返回IGroupingTKey,TElement支持多键、投影分组值 场景报表分组、统计分类数据// 单键分组按年龄分组 var group users.GroupBy(u u.Age); foreach(var g in group) { int age g.Key; int count g.Count(); } // 多键分组匿名类复合键 var multiGroup users.GroupBy(u new {u.Age, u.Gender}); // 分组同时映射元素 var groupName users.GroupBy(uu.Age, uu.Name);十一、生成序列方法无数据源创建集合延迟1. Range(start, count) 生成连续数字var nums Enumerable.Range(1,10); // 1~102. Repeat(value, count) 重复生成指定值var fiveZero Enumerable.Repeat(0,5);3. Empty() 返回空 IEnumerable场景方法返回IEnumerable无数据时避免null十二、zip 配对合并序列延迟Zip 将两个序列按位置一一配对长度取最短场景两个列表一一对应合并var a new Listint{1,2,3}; var b new Liststring{a,b,c}; var zip a.Zip(b,(x,y)new{Numx,Stry});关键核心知识点1. 延迟执行 vs 立即执行 区分延迟仅定义查询遍历才执行Where/Select/SelectMany/OrderBy/Take/Skip/Distinct/GroupBy/Concat/Union/Except/Intersect/Zip/OfType 优点多次拼接查询只会执行一次EF 可拼接SQL优化立即调用时直接执行查询加载数据ToList/ToArray/ToDictionary/Count/Sum/Min/Max/Average/Aggregate/First/Any/All/Single/Contains 一旦调用SQL/内存计算立刻执行结果存入容器2. IQueryable VS IEnumerable 使用场景数据库查询EF Core优先 IQueryableWhere/Select/Take 会翻译为SQL只拉取需要数据性能高复杂逻辑无法转SQL本地方法、自定义函数加.AsEnumerable()切换内存LINQ内存集合List/Array只能用 IEnumerable3. 高频业务场景速查表需求推荐LINQ方法分页Skip Take CountDTO转换Select 匿名类/实体一对多展开SelectMany主键查单条SingleOrDefault判断数据存在Any()分组统计GroupBy Count/Sum去重Distinct集合对比差异Except/Intersect/Union多条件排序OrderBy ThenBy列表转字典索引ToDictionary内存落地查询结果ToList()4. 避坑提醒IQueryable 不要在循环内多次 ToList()会重复查库First()/Single() 无数据抛异常业务统一用 *OrDefaultOrderBy 后必须 ThenBy不能连续两个 OrderBy后者覆盖前者Count() 0 性能远差于 Any()判断存在一律 AnyEF 中 Last() 会拉取全表再取最后一条大数据禁用改用 OrderByDescending FirstOrDefault