You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

返回Select()与yield return的差异:代码、性能等对比

Select() 与 yield return 的核心区别

一、底层生成代码差异

使用 Select() 的情况

Select 是 LINQ 内置的投影方法,调用后会返回一个内置迭代器类(比如 SelectEnumerableIterator<TInput, TResult>)。这个类会持有原始集合的引用,以及你传入的投影委托。当枚举这个返回值时,每次调用 MoveNext() 都会从原始集合取出下一个元素,再执行投影委托完成转换。

使用 yield return 的情况

带 yield return 的方法,编译器会自动生成一个状态机类,实现 IEnumerable<T> 和 IEnumerator<T> 接口。这个状态机包含记录执行位置的状态字段,以及封装了整个 foreach 逻辑的 MoveNext() 方法:每次调用 MoveNext() 时,代码会从上次暂停的位置(上一个 yield return 处)继续执行,直到遇到下一个 yield return 或遍历结束。

二、延迟执行的细节差异

两者都遵循延迟执行原则(逻辑不会在方法调用时立即执行,而是等到枚举返回的 IEnumerable 时才触发),但触发逻辑有细微区别:

  • Select 的投影逻辑完全依赖委托调用,每次枚举元素时才触发对应元素的投影操作。
  • yield return 的逻辑直接内联在状态机的 MoveNext() 中,没有委托调用的开销,执行流程更贴近手写的迭代器。

三、性能表现差异

大多数场景下两者性能差异极小,但特定场景下会有区别:

  • 委托调用开销:Select 每次投影都要触发一次委托调用,而 yield return 是直接执行逻辑,当投影逻辑非常简单时,yield return 会略快一点。
  • 多迭代器嵌套场景:如果需要在投影时跳过元素,用 yield return 可以直接在 foreach 里加 continue;而 Select 需要配合 Where 方法,多一层迭代器嵌套,此时 yield return 的性能更优。
  • 多次枚举的影响:两者每次枚举都会重新遍历原始集合并执行逻辑(除非原始集合是缓存过的,比如 List),性能表现一致。

四、功能灵活性差异

yield return 的灵活性远高于 Select:

  • 控制遍历流程:可以在 foreach 中自由使用 continue、break,甚至在一个元素的处理中多次 yield return(比如把一个元素拆分成多个结果输出)。
  • 复杂逻辑支持:能处理嵌套循环、中途执行额外操作(比如日志记录、资源清理)等场景,而 Select 只能做单一的元素投影,复杂逻辑需要组合多个 LINQ 方法(比如 SelectMany、Where),可读性和维护性不如 yield return。
  • 异常处理:虽然两者都是在枚举时抛出异常,但 yield return 可以在遍历过程中灵活捕获和处理异常,而 Select 的异常只能在委托内部处理。

示例对比

你给出的两个示例功能等价,但底层实现不同:

  • Select 版本返回一个持有原始集合和投影委托的迭代器,枚举时逐个调用委托转换元素。
  • yield return 版本由编译器生成状态机,枚举时直接执行 foreach 内的逻辑,跳过委托调用环节。

内容的提问来源于stack exchange,提问作者Luiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 07:53:17