如何向C#迭代器传递值?类比JavaScript生成器实现
在C#中模拟JavaScript生成器的传值行为
C#原生的yield语法糖本身不支持直接像JavaScript生成器那样,通过迭代器的移动方法传递值给yield表达式的结果——核心原因是C#的IEnumerator<T>接口定义的MoveNext()是无参方法,没有预留传递输入值的能力。
不过可以通过自定义迭代器包装类,结合yield的特性来模拟这种传值行为,不需要使用通道类(如BlockingCollection),仅借助yield语法糖和自定义逻辑实现:
实现思路
- 自定义一个带输入能力的迭代器容器类,提供
Send()方法接收外部传入的值; - 在迭代器逻辑中(用
yield return实现),通过容器类的方法获取传入的值; - 容器类内部协调
MoveNext()的调用和输入值的传递。
代码示例
public class Generator<TInput, TOutput> { private readonly IEnumerator<TOutput> _enumerator; private TInput _pendingInput; private bool _hasPendingInput; public Generator(Func<Generator<TInput, TOutput>, IEnumerator<TOutput>> generatorFactory) { _enumerator = generatorFactory(this); } // 模拟JS的next(),传入值并获取迭代器输出 public bool Send(TInput input, out TOutput output) { _pendingInput = input; _hasPendingInput = true; var moved = _enumerator.MoveNext(); output = moved ? _enumerator.Current : default; return moved; } // 供迭代器内部获取传入的值 public TInput GetInput() { _hasPendingInput = false; return _pendingInput; } } // 定义带输入接收的迭代器逻辑 public static IEnumerator<string> NumberProcessor(Generator<int, string> generator) { // 接收第一个输入值 int firstNum = generator.GetInput(); yield return $"处理第一个数字:{firstNum * 2}"; // 接收第二个输入值 int secondNum = generator.GetInput(); yield return $"处理第二个数字:{secondNum + 10}"; } // 调用示例 var generator = new Generator<int, string>(NumberProcessor); if (generator.Send(5, out var result1)) { Console.WriteLine(result1); // 输出:处理第一个数字:10 } if (generator.Send(15, out var result2)) { Console.WriteLine(result2); // 输出:处理第二个数字:25 }
注意事项
- 这种方式本质是对原生迭代器的包装,并非直接扩展
IEnumerator<T>接口; - 迭代器内部的
GetInput()调用必须和外部的Send()调用一一对应,否则会出现值传递错误; - 如果需要更复杂的交互(比如异常传递、终止信号),可以在自定义容器类中扩展对应的方法。
内容的提问来源于stack exchange,提问作者Bondolin
相关产品推荐
相关产品推荐

