当我有一个代码块时
static void Main()
{
foreach (int i in YieldDemo.SupplyIntegers())
{
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
class YieldDemo
{
public static IEnumerable<int> SupplyIntegers()
{
yield return 1;
yield return 2;
yield return 3;
}
}
我可以将收益率背后的原理解释为
- Main() 调用 SupplyIntegers()
|1| |2| |3| are stored in contiguous memory block.Pointer of "IEnumerator" Moves to |1|
- 控制从 SupplyInteger() 返回到 Main()。
- Main() 打印值
- 指针移至|2|,依此类推。
澄清:
(1) 通常我们会在函数内部允许有一个有效的 return 语句。
当存在多个yield return,yield return,... 语句时,C# 会如何处理?
(2) 一旦遇到返回,控制就无法再次返回
SupplyIntegers(),如果允许,Yield 不会再次从 1 开始吗?我的意思是收益率1?
不——远非如此;我给你写一个长手写的版本……太蹩脚了!
请注意,如果您了解foreach
实际上是:
using(var iterator = YieldDemo.SupplyIntegers().GetEnumerator()) {
int i;
while(iterator.MoveNext()) {
i = iterator.Current;
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
static class Program
{
static void Main()
{
foreach (int i in YieldDemo.SupplyIntegers())
{
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
}
class YieldDemo
{
public static IEnumerable<int> SupplyIntegers()
{
return new YieldEnumerable();
}
class YieldEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new YieldIterator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class YieldIterator : IEnumerator<int>
{
private int state = 0;
private int value;
public int Current { get { return value; } }
object IEnumerator.Current { get { return Current; } }
void IEnumerator.Reset() { throw new NotSupportedException(); }
void IDisposable.Dispose() { }
public bool MoveNext()
{
switch (state)
{
case 0: value = 1; state = 1; return true;
case 1: value = 2; state = 2; return true;
case 2: value = 3; state = 3; return true;
default: return false;
}
}
}
}
正如你所看到的,它在迭代器中构建了一个状态机,状态机的进度为MoveNext
。我已经使用了该模式state
字段,您可以看到这对于更复杂的迭代器是如何工作的。
重要的:
- 迭代器块中的任何变量都会变成fields在状态机上
- 如果你有一个
finally
块(包括using
),它进入Dispose()
- 导致的代码部分
yield return
成为一个case
(大致)
-
yield break
成为一个state = -1; return false;
(或类似)
C# 编译器执行此操作的方式非常复杂,但它使编写迭代器变得轻而易举。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)