收益率工作模式
当我有一个代码块时,
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;
}
}
我可以将yield return背后的原理解释为
- Main()调用SupplyIntegers()
|1| |2| |3|存储在连续的内存块中。“IEnumerator”的指针移动到 |1|
- 控制从 SupplyInteger() 返回到 Main()。
- Main() 打印值
- Pointer Moves to |2|,依此类推。
说明:
(1) 通常我们会在函数内部允许有一个有效的 return 语句。 当存在多个yield return、yield return、...语句时,C# 会如何处理?
(2) 一旦遇到返回,控制就无法再次返回 SupplyIntegers(),如果允许,Yield 不会再次从 1 开始吗?我的意思是收益率1?
When i have a code block
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;
}
}
can i interpret the principle behind yield return as
- Main() calls the SupplyIntegers()
|1| |2| |3| are stored in contiguous memory block.Pointer of "IEnumerator" Moves to |1|
- Control returns from SupplyInteger() to Main().
- Main() prints the value
- Pointer Moves to |2|, and so on.
Clarifications :
(1) Normally we will have one valid return statement is allowed inside a function.How does
C# treats when multiple yield return ,yield return,... statements are present?
(2) Once the return is encountered there is no way for control again coming back to
SupplyIntegers(), in case it is allowed won't the Yield again starts from 1 ? I mean yield return 1?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(4)
简而言之,迭代器块(或者带有 yield
语句的方法,如果可以的话)被编译器转换为编译器生成的类。此类实现 IEnumerator
且 yield
语句转换为该类的“状态”。
例如,这:
yield return 1;
yield return 2;
yield return 3;
可能会转换成类似于:
switch (state)
{
case 0: goto LABEL_A;
case 1: goto LABEL_B;
case 2: goto LABEL_C;
}
LABEL_A:
return 1;
LABEL_B:
return 2;
LABEL_C:
return 3;
迭代器块可以被视为抽象状态机。此代码将由 IEnumerator
的方法调用。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
不——远非如此;我给你写一个长手写的版本……太蹩脚了!
请注意,如果您了解
foreach
实际上是有帮助的:如您所见,它在迭代器中构建一个状态机,状态机通过
MoveNext
进行。我使用了带有state
字段的模式,您可以看到这对于更复杂的迭代器是如何工作的。重要的是:
finally
块(包括using
),迭代器块中的任何变量都会成为状态机上的字段Dispose()
yield return
的case
(粗略地)yield break
变成 <代码>状态=-1; return false; (或类似)C# 编译器执行此操作的方式非常复杂,但它使编写迭代器变得轻而易举。
Nope - far from it; I'll write a long-hand version for you... it is too grungy!
Note it also helps if you understand that the
foreach
is actually:As you can see, it builds a state machine in the iterator, with the state machine progressed by
MoveNext
. I've used the pattern with astate
field, as you can see how this would work for more complex iterators.Importantly:
finally
block (includingusing
), it goes in theDispose()
yield return
become acase
(roughly)yield break
becomes astate = -1; return false;
(or similar)The way the C# compiler does this is very complicated, but it makes writing iterators a breeze.