应根据业务是否允许“不存在”选择:必须存在用First(抛异常),可选则用FirstOrDefault(返回默认值);EF Core中优先用FirstOrDefaultAsync,避免误用FirstAsync导致编译失败。

First 和 FirstOrDefault 用哪个?看要不要抛异常
关键区别就一条:找不到元素时,First 直接抛 InvalidOperationException,而 FirstOrDefault 返回类型的默认值(比如 null 对于引用类型,0 对于 int)。别硬记“FirstOrDefault 更安全”,得看业务逻辑是否允许“不存在”这个结果。
常见错误现象:First 在空集合上运行直接崩,日志里只看到 Sequence contains no elements,没做 try-catch 就挂了;反过来,用 FirstOrDefault 拿到 null 后直接调用 .ToString(),又触发 NullReferenceException。
- 查用户配置项且**必须存在** → 用
First,让问题早点暴露 - 查可选筛选条件(如“找状态为 Draft 的订单,没有就算了”)→ 用
FirstOrDefault,之后加if (result != null)判断 - 对值类型(如
int?、DateTime?)用FirstOrDefault更自然,避免装箱或额外判空
带条件的 FirstOrDefault(x => x.Id == 123) 为什么比 Where(...).First() 快?
因为 FirstOrDefault 是“找到第一个就停”,而 Where(...).First() 先生成一个中间迭代器,再从头遍历——多一次委托调用 + 多一层状态管理。实际性能差不了几纳秒,但语义清晰度和可读性差一截。
使用场景:数据库查询(EF Core)里尤其明显,FirstOrDefault 能翻译成 SQL 的 TOP 1,Where().First() 有时会先拉回全量再内存筛选(取决于 Provider 实现)。
- 永远优先写
list.FirstOrDefault(x => x.Name == "abc"),而不是list.Where(x => x.Name == "abc").First() - 如果条件复杂(比如要同时满足多个字段 + 排序),再考虑用
Where+OrderBy+FirstOrDefault组合 - EF Core 中,
FirstOrDefault支持直接传表达式树,First同理;但别在它后面链式调用.Select(x => x.Name)再FirstOrDefault,这会让生成 SQL 变复杂甚至失败
FirstOrDefault 返回 null 却没报错?检查泛型约束和类型推导
有时候写了 var user = users.FirstOrDefault(u => u.Age > 18),结果 user 是 null,但 IDE 没警告,运行也不崩——不是代码错了,是 users 类型是 IEnumerable,FirstOrDefault 返回 User,而 User 是 class,所以默认值就是 null。但如果 users 是 IEnumerable,返回的就是 0,不是 null。
容易踩的坑:把 FirstOrDefault 结果直接当非空对象用,尤其在启用了 C# 8+ 可空引用类型(NRT)但没配好 #nullable enable 时,编译器不会提醒你判空。
- 开启项目级可空检查(
)后,enable FirstOrDefault对引用类型返回的是User?,IDE 会标黄提醒你解引用前要判空 - 别依赖变量名猜类型,用 Ctrl+鼠标悬停看实际推导出的返回类型是
User还是User? - 如果集合是
IEnumerable且T是 struct,FirstOrDefault永远不会返回null,这时候用== null判空是无效的(编译不过)
EF Core 中 FirstOrDefault 异步方法叫 FirstOrDefaultAsync,别手滑写成 FirstAsync
EF Core 6+ 里,同步方法有 First / FirstOrDefault,对应异步是 FirstAsync / FirstOrDefaultAsync。但很多人顺手写成 FirstAsync 却传了 predicate,结果编译失败:因为 FirstAsync 没有接收表达式的重载,只有无参版;真正支持条件的是 FirstOrDefaultAsync。
错误信息典型长这样:The type arguments for method 'Queryable.FirstOrDefaultAsync —— 其实就是你写了 ctx.Users.FirstAsync(u => u.Id == id),但该方法根本不存在。
- 一律用
FirstOrDefaultAsync,哪怕你确定数据一定存在;异步操作本身就有不确定性,没必要为“一定存在”冒阻塞风险 -
FirstAsync只接受IQueryable,不接受 lambda,所以只能用于“取第一个”,不能带 where 条件 - 别在 .NET 5 或更早版本用这些 Async 方法,它们是 EF Core 5+ 才稳定支持的,低版本会 fallback 到同步执行
事情说清了就结束。最常漏掉的是:可空引用类型开关没开,导致 FirstOrDefault 返回 null 却毫无提示;还有就是 EF Core 里把 FirstAsync 当成万能异步版乱用。










