yield statement implementation
我想以一种易于理解的形式了解有关
我已经阅读过
另外,你什么时候使用屈服点?
以下是从陈瑞蒙的博客开始:
- C语言中迭代器的实现及其后果(第1部分)
- C语言中迭代器的实现及其后果(第2部分)
- C语言中迭代器的实现及其后果(第3部分)
您可以使用Reflector来查看编译器是如何实现它的。
当您想停止返回结果时,使用
正如梅尔达所说,它建立了一个状态机。
除了使用Reflector(另一个很好的建议),您可能会发现我关于迭代器块实现的文章很有用。如果没有
让我们倒回去一点:
实际上,这并不完全像使用将在后台使用的内置实现,而是编译器通过实现一个相关接口(包含
(有限)状态机只是一段代码,根据您在代码中的位置(取决于前一个状态,输入)转到另一个状态操作,当您使用和生成方法返回类型为
这正是C编译器/Roslyn要做的:检查是否存在
如果您对状态机以及编译器如何重写迭代的细节感兴趣,可以在GitHub上查看这些链接:
IteratorRewriter 源代码StateMachineRewriter :上述源代码的父类
小贴士1:
如前所述,状态机在
编译器从用户代码生成的代码看起来不太"好",主要是因为编译器在这里和那里添加了一些奇怪的前缀和后缀。
例如,代码:
1 2 3 4 5 6 7 8 9 10 11 12 | public class TestClass { private int _iAmAHere = 0; public IEnumerator<int> DoSomething() { var start = 1; var stop = 42; var breakCondition = 34; var exceptionCondition = 41; var multiplier = 2; // Rest of the code... with some yield keywords somewhere below... |
编译后,与上述代码段相关的变量和类型如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class TestClass { [CompilerGenerated] private sealed class <DoSomething>d__1 : IEnumerator<int>, IDisposable, IEnumerator { // Always present private int <>1__state; private int <>2__current; // Containing class public TestClass <>4__this; private int <start>5__1; private int <stop>5__2; private int <breakCondition>5__3; private int <exceptionCondition>5__4; private int <multiplier>5__5; |
关于状态机本身,让我们来看一个非常简单的例子,其中有一个用于生成一些偶数/奇数的伪分支。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class Example { public IEnumerator<string> DoSomething() { const int start = 1; const int stop = 42; for (var index = start; index < stop; index++) { yield return index % 2 == 0 ?"even" :"odd"; } } } |
将在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <start>5__1 = 1; <stop>5__2 = 42; <index>5__3 = <start>5__1; break; case 1: <>1__state = -1; goto IL_0094; case 2: { <>1__state = -1; goto IL_0094; } IL_0094: <index>5__3++; break; } if (<index>5__3 < <stop>5__2) { if (<index>5__3 % 2 == 0) { <>2__current ="even"; <>1__state = 1; return true; } <>2__current ="odd"; <>1__state = 2; return true; } return false; } |
正如您所看到的,这个实现远不是简单的,但它确实完成了任务!
小技巧2:
关于使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public interface IEnumerable<out T> : IEnumerable { new IEnumerator<T> GetEnumerator(); } public interface IEnumerator<out T> : IDisposable, IEnumerator { T Current { get; } } public interface IEnumerator { bool MoveNext(); object Current { get; } void Reset(); } |
您还可以使用不同的路径/分支和编译器重写的完整实现来检查这个示例。
这是使用sharplab创建的,您可以使用该工具尝试不同的
关于问题的第二部分,即
It specifies that an iterator has come to an end. You can think of
yield break as a return statement which does not return a value.