LINQ常见错误包括:null引用异常需前置x!=null过滤;EF Core中?.可能触发客户端求值;字符串比较应指定StringComparison;OrderBy后误用OrderBy会覆盖排序;GroupBy后需显式枚举分组内元素;延迟执行需注意重复执行和Count()/Any()性能差异。

用 Where 筛选时,别直接写 null 判断条件
常见错误是写成 list.Where(x => x.Name != null && x.Name.Contains("a")),看似没问题,但一旦 x 本身为 null,运行时就抛 NullReferenceException。尤其在数据库查询(如 EF Core)中,null 检查会被转成 SQL,但内存集合(List<T>)不会自动防御。
- 安全写法:先用
OfType<T>()过滤掉null元素,或用Where(x => x != null)显式前置过滤 - EF Core 场景下,
Where(x => x.Name?.Length > 0)中的空条件运算符(?)可能无法翻译成 SQL,会触发客户端求值(Client Evaluation),性能骤降且可能报错 - 字符串比较注意文化敏感性:
Contains("A", StringComparison.OrdinalIgnoreCase)比默认更可靠
OrderBy 和 ThenBy 的链式调用顺序不能反
OrderBy 是主排序,之后所有 ThenBy(升序)或 ThenByDescending(降序)才构成多级排序。如果误把第二个条件也写成 OrderBy,前面的排序会被覆盖——因为每次 OrderBy 都返回新序列并重排。
- 正确:
list.OrderBy(x => x.Age).ThenBy(x => x.Name) - 错误:
list.OrderBy(x => x.Age).OrderBy(x => x.Name)→ 只按Name排,Age无效 - 升序/降序混用示例:
OrderBy(x => x.Department).ThenByDescending(x => x.Salary) - 注意:对大集合排序前,确认是否已索引(如数据库字段);内存中排序无索引优化,
O(n log n)开销真实存在
用 GroupBy 分组后,别直接遍历 IGrouping<K, V> 的 Key 就以为拿到全部信息
GroupBy 返回的是 IEnumerable<IGrouping<K, V>>,每个 IGrouping 既是 IEnumerable<V>,又带一个 Key 属性。新手常只取 g.Key,却忘了分组内原始元素需要显式枚举(比如用 g.ToList() 或 g.Count())。
- 典型误用:
var groups = list.GroupBy(x => x.Type); foreach (var g in groups) Console.WriteLine(g.Key);→ 只打印了分组键,没处理数据 - 常用组合:
GroupBy(...).Select(g => new { Type = g.Key, Count = g.Count(), Items = g.ToList() }) - EF Core 中慎用
GroupBy后接复杂投影(如new { ... }),部分表达式无法翻译成 SQL,会触发客户端分组(Client Evaluation),导致全量拉取再分组,内存和网络开销陡增
延迟执行不是“永远不执行”,ToList/ToArray 才真正触发
所有 LINQ 查询操作符(Where、OrderBy、GroupBy)返回的是 IQueryable<T> 或 IEnumerable<T>,它们只是“查询定义”,不立刻执行。真正执行发生在你开始遍历(foreach)、或调用强制执行方法时。
- 常见陷阱:反复调用同一个查询变量,比如
var q = data.Where(...); var a = q.Count(); var b = q.ToList();→ 执行两次(数据库查两次 / 内存集合遍历两次) - 解决办法:需要多次使用结果时,先
.ToList()或.ToArray()落地为具体集合 - 注意
Count()和Any()的差异:对数据库,Any()生成EXISTS,比Count() > 0高效得多;对内存集合,Any()可提前退出,Count()必须遍历完
List<T> 上跑得飞快,在 EF Core 的 IQueryable<T> 上却可能因某个函数无法翻译而崩在运行时,或者悄悄退化到客户端执行。动手前,先想清楚:这是内存操作,还是数据库查询?


















