yield 是如何枚举的?
How is yield an enumerable?
我一直在研究 yield
和 IEnumerable
,现在我很好奇为什么或如何使用以下代码片段:
public class FakeList : IEnumerable<int>
{
private int one;
private int two;
public IEnumerator<int> GetEnumerator()
{
yield return one;
yield return two;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
现在编译器如何转换这个:
public IEnumerator<int> GetEnumerator()
{
yield return one;
yield return two;
}
变成IEnumerator<int>
?
使用yield return
时,编译器会为您生成一个枚举器class。所以实际使用的代码比两个 return 语句复杂得多。编译器为您将所有必要的代码添加到 return 枚举器,它迭代 yield return
.
的结果
这是从您的 FakeList.GetEnumerator()
:
生成的代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
public class FakeList : IEnumerable<int>, IEnumerable
{
private int one;
private int two;
[IteratorStateMachine(typeof(<GetEnumerator>d__2))]
public IEnumerator<int> GetEnumerator()
{
yield return this.one;
yield return this.two;
}
IEnumerator IEnumerable.GetEnumerator() =>
this.GetEnumerator();
[CompilerGenerated]
private sealed class <GetEnumerator>d__2 : IEnumerator<int>, IDisposable, IEnumerator
{
private int <>1__state;
private int <>2__current;
public FakeList <>4__this;
[DebuggerHidden]
public <GetEnumerator>d__2(int <>1__state)
{
this.<>1__state = <>1__state;
}
private bool MoveNext()
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
this.<>2__current = this.<>4__this.one;
this.<>1__state = 1;
return true;
case 1:
this.<>1__state = -1;
this.<>2__current = this.<>4__this.two;
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = -1;
return false;
}
return false;
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
void IDisposable.Dispose()
{
}
int IEnumerator<int>.Current =>
this.<>2__current;
object IEnumerator.Current =>
this.<>2__current;
}
}
你看到<GetEnumerator>d__2
class了吗?那是根据你的两个yield return
生成的。
当编译器看到 yield return
或 yield break
时,它获取函数并将其逻辑转换为实现状态机的 class。然后在调用该方法时返回此 class 的一个实例。
C# In Depth 有一节介绍代码的外观。
这是一台发电机。
我不能说后面的编译器是如何工作的,但是当你这样做的时候:
yield return x;
您不会像经典 return 那样离开函数,而是 return 一个值,然后继续执行函数。
如果我没记错的话,真正的可枚举和这个之间有一点区别,如果你不使用方法将你的生成器转换成真正的可枚举(取决于你想要完成的事情)你可能会有一些麻烦。
我一直在研究 yield
和 IEnumerable
,现在我很好奇为什么或如何使用以下代码片段:
public class FakeList : IEnumerable<int>
{
private int one;
private int two;
public IEnumerator<int> GetEnumerator()
{
yield return one;
yield return two;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
现在编译器如何转换这个:
public IEnumerator<int> GetEnumerator()
{
yield return one;
yield return two;
}
变成IEnumerator<int>
?
使用yield return
时,编译器会为您生成一个枚举器class。所以实际使用的代码比两个 return 语句复杂得多。编译器为您将所有必要的代码添加到 return 枚举器,它迭代 yield return
.
这是从您的 FakeList.GetEnumerator()
:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
public class FakeList : IEnumerable<int>, IEnumerable
{
private int one;
private int two;
[IteratorStateMachine(typeof(<GetEnumerator>d__2))]
public IEnumerator<int> GetEnumerator()
{
yield return this.one;
yield return this.two;
}
IEnumerator IEnumerable.GetEnumerator() =>
this.GetEnumerator();
[CompilerGenerated]
private sealed class <GetEnumerator>d__2 : IEnumerator<int>, IDisposable, IEnumerator
{
private int <>1__state;
private int <>2__current;
public FakeList <>4__this;
[DebuggerHidden]
public <GetEnumerator>d__2(int <>1__state)
{
this.<>1__state = <>1__state;
}
private bool MoveNext()
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
this.<>2__current = this.<>4__this.one;
this.<>1__state = 1;
return true;
case 1:
this.<>1__state = -1;
this.<>2__current = this.<>4__this.two;
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = -1;
return false;
}
return false;
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
void IDisposable.Dispose()
{
}
int IEnumerator<int>.Current =>
this.<>2__current;
object IEnumerator.Current =>
this.<>2__current;
}
}
你看到<GetEnumerator>d__2
class了吗?那是根据你的两个yield return
生成的。
当编译器看到 yield return
或 yield break
时,它获取函数并将其逻辑转换为实现状态机的 class。然后在调用该方法时返回此 class 的一个实例。
C# In Depth 有一节介绍代码的外观。
这是一台发电机。 我不能说后面的编译器是如何工作的,但是当你这样做的时候:
yield return x;
您不会像经典 return 那样离开函数,而是 return 一个值,然后继续执行函数。
如果我没记错的话,真正的可枚举和这个之间有一点区别,如果你不使用方法将你的生成器转换成真正的可枚举(取决于你想要完成的事情)你可能会有一些麻烦。