CSharp - c#的yield关键字的用途是什么?

  显示原文与译文双语对照的内容

中,如何只公开一个 IList <> 问题的Fragment其中一个答案有以下代码 Fragment:


IEnumerable<object> FilteredList()
{
 foreach( object item in FullList )
 {
 if( IsItemInPartialList( item )
 yield return item;
 }
}

yield关键字做了什么? 我看到它在几个地方引用过,还有一个问题,但是我还没有完全弄清楚它到底是什么。 我习惯于从一个线程屈服到另一个线程的感觉,但这似乎并不相关。

时间:

yield 关键字实际上在这里做很多事情。 函数返回一个实现IEnumerable接口的对象。 如果调用函数在这里对象上启动 foreach-ing,函数将再次调用,直到它"收益率"。 这是 C# 2.0中引入的语法糖。 在早期版本中,你必须创建自己的IEnumerable和IEnumerator对象来完成这样的操作。

理解这样的代码最简单的方法是输入一个示例,设置一些断点并查看发生了什么。

尝试执行以下步骤:


public void Consumer()
{
 foreach(int i in Integers())
 {
 Console.WriteLine(i.ToString());
 }
}

public IEnumerable<int> Integers()
{
 yield return 1;
 yield return 2;
 yield return 4;
 yield return 8;
 yield return 16;
 yield return 16777216;
}

最近,Raymond Chen也在 yield 关键字上运行了一系列有趣的文章。

虽然它名义上是用于实现一个迭代器模式,但可以很容易地推广到一个状态机。 引用Raymond没有意义,最后一部分还链接到其他使用( entin中的例子是特别的,展示了如何编写异步安全代码) 。

直观地,关键字从函数返回一个值而不离开它,换句话说,在你的代码示例中返回当前的item 值,然后继续循环。 更正式的是,编译器使用它为迭代器生成代码。 迭代器是返回 IEnumerable 对象的函数。 MSDN web有几个关于它们的文章。

"收益率返回"与枚举数一起使用。 在每个yield语句的调用上,控制被返回给调用方,但它确保被调用方的状态保持不变。 由于这个原因,当调用者枚举下一个元素时,它将在yield语句之后立即从语句中继续执行被调用方方法。

让我们用一个例子来理解它。 在这个例子中,对应于每一行我提到了执行流程的顺序。


 static void Main(string[] args)
 {
 foreach (int fib in Fibs(6))//1, 5
 {
 Console.WriteLine(fib +"");//4, 10
 } 
 }

 static IEnumerable<int> Fibs(int fibCount)
 {
 for (int i = 0, prevFib = 0, currFib = 1; i <fibCount; i++)//2
 {
 yield return prevFib;//3, 9
 int newFib = prevFib + currFib;//6
 prevFib = currFib;//7
 currFib = newFib;//8
 }
 }

同时,为每个枚举维护状态。 假设我有另一个调用 Fibs() 方法,然后状态将被重置。

...