在C#中,yield return 是实现自定义迭代器最简洁、高效的方式,它让方法能按需生成序列,无需一次性构造整个集合,节省内存且支持延迟执行。
yield return 的基本用法
被 yield return 修饰的方法必须返回
IEnumerable<t></t>或
IEnumerator<t></t>,且不能有
return语句(除
return;外),也不能有
ref/
out参数或
try-catch块(除非
catch内无
yield,且
finally中不能有
yield)。
每次调用迭代器的
MoveNext(),代码从上一次
yield return暂停处继续执行,直到下一个
yield return或方法结束。 每个
yield return返回一个元素,控制权交还给调用方
yield break可提前终止迭代,等效于自然退出 编译器会将含
yield的方法自动转换为状态机类(编译后可见)
实现简单数值序列的迭代器
例如生成 1 到 n 的平方数:
public static IEnumerable<int> Squares(int n)
{
for (int i = 1; i <= n; i++)
{
yield return i * i;
}
}调用时可直接用于
foreach或 LINQ:
foreach (int sq in Squares(5))
Console.WriteLine(sq); // 输出 1, 4, 9, 16, 25注意:该方法不会立即执行循环,只有在第一次枚举时才开始计算——这就是延迟执行。
用 yield return 实现树的中序遍历
递归 + yield 是处理嵌套结构的常用模式。假设有一个二叉树节点类:
public class TreeNode
{
public int Value { get; set; }
public TreeNode Left { get; set; }
public TreeNode Right { get; set; }
}中序遍历(左-根-右)可这样写:
public static IEnumerable<int> InOrder(TreeNode node)
{
if (node == null) yield break;
<pre class="brush:php;toolbar:false;">foreach (var v in InOrder(node.Left)) yield return v;
yield return node.Value;
foreach (var v in InOrder(node.Right)) yield return v;}
这种方式逻辑清晰,避免手动维护栈,也保持了延迟求值特性——遍历到哪才计算到哪。
注意事项与常见误区
yield return 看似简单,但容易踩坑:
不能在匿名方法、lambda 表达式或异步方法(async)中使用
yield局部变量在多次迭代中会被保留(闭包行为),注意引用生命周期 每次调用迭代器方法都会创建新的枚举器,互不影响;但若方法内捕获了外部可变状态,需谨慎线程安全 调试时无法在
yield return行设断点(VS 中可能跳过),建议用日志或拆分逻辑辅助排查
基本上就这些。掌握
yield return后,写数据流处理、配置解析、文件逐行读取等场景会变得非常自然和轻量。
