为什么 IEnumerator.MoveNext 在 GetCurrent 之前调用?
Why IEnumerator.MoveNext is called before GetCurrent?
我对 IL 完全陌生,但据我所知 MoveNext
应该在 Current
之前调用,假设我们有这样的 foreach 语句:
foreach (var i in Enumerable.Empty<string>())
{
}
如果我们查看生成的 IL,我们会发现 Current 实际上首先被调用:
IL_0014: br.s IL_001f
IL_0016: ldloc.1
IL_0017: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_001c: stloc.0
IL_001d: nop
IL_001e: nop
IL_001f: ldloc.1
IL_0020: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0025: stloc.2
IL_0026: ldloc.2
IL_0027: brtrue.s IL_0016
IL_0029: leave.s IL_003b
问题是为什么?
IL_0014: br.s IL_001f
根据 MSDN,br.s
Unconditionally transfers control to a target instruction (short form).
引用的地址是调用MoveNext
的指令。
IL_001f: ldloc.1
IL_0020: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
我对 IL 完全陌生,但据我所知 MoveNext
应该在 Current
之前调用,假设我们有这样的 foreach 语句:
foreach (var i in Enumerable.Empty<string>())
{
}
如果我们查看生成的 IL,我们会发现 Current 实际上首先被调用:
IL_0014: br.s IL_001f
IL_0016: ldloc.1
IL_0017: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
IL_001c: stloc.0
IL_001d: nop
IL_001e: nop
IL_001f: ldloc.1
IL_0020: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0025: stloc.2
IL_0026: ldloc.2
IL_0027: brtrue.s IL_0016
IL_0029: leave.s IL_003b
问题是为什么?
IL_0014: br.s IL_001f
根据 MSDN,br.s
Unconditionally transfers control to a target instruction (short form).
引用的地址是调用MoveNext
的指令。
IL_001f: ldloc.1
IL_0020: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()