请解释 C# 中迭代器(iterator)的用途,并说明 yield 关键字在其中扮演的角色及其工作机制。
考察说明
考查对 C# 迭代器模式及 yield 语法糖的理解,包括其延迟执行和状态保存特性。
回答思路
- 【回答框架 1】迭代器是 C# 中实现迭代器模式的核心机制,它允许类型通过实现 IEnumerable 或 IEnumerable<T> 接口来支持 foreach 遍历。迭代器的核心价值在于提供一种统一、简洁的方式来遍历集合元素,而无需暴露底层数据结构,同时支持延迟执行,即元素按需生成,而非一次性全部加载。
- 【回答框架 2】yield 关键字是迭代器块的语法糖,它提供 return 和 break 两种形式。yield return 用于逐个返回元素,而 yield break 用于提前终止迭代。当编译器遇到包含 yield 的方法时,会将其转换成一个状态机,该状态机实现了 IEnumerator 接口,从而保存迭代过程中的所有局部变量和当前执行位置。
- 【回答框架 3】状态机机制是 yield 工作的核心:首次 MoveNext 调用时,执行到第一个 yield return 并保存状态;后续每次 MoveNext 从上次暂停处继续,直到方法结束或遇到 yield break。这种设计使迭代器无需维护显式的索引或集合,尤其适用于生成无限序列、遍历树形结构或处理大数据流。
- 【回答框架 4】相比手动实现 IEnumerator,yield 大幅简化代码,减少样板代码和出错可能。但使用时需注意:yield 不能在 try-catch 块中使用(除非 catch 中不含 yield),但可以在 try-finally 中使用;且迭代器方法不会被立即执行,而是延迟到 foreach 或手动调用 MoveNext 时。
- 【回答框架 5】在实际开发中,yield 常用于 LINQ 内部、异步流(IAsyncEnumerable<T>)以及通过迭代器实现惰性求值的场景。如果集合较小,使用 List 预生成可能更直观;但面对大数据集或需要按需计算时,yield 能显著降低内存占用。
- 【关键点 1】yield return 逐个返回元素,yield break 终止迭代,编译器自动生成状态机保存执行上下文。
- 【关键点 2】迭代器支持延迟执行,元素在遍历时才生成,适合处理大数据或无限序列。
- 【关键点 3】使用 yield 可简化自定义集合的遍历实现,避免手动编写 IEnumerator。
- 【易错点 1】迭代器方法不会立即执行,若需立即执行需调用 ToList() 或 ToArray()。
- 【易错点 2】yield 在 try-catch 中使用受限,可能导致编译错误。
- 【易错点 3】多次遍历同一个迭代器会每次重新执行方法,若需复用需缓存结果。