[英]What does this compiler-generated enumerator mean?
我写了一个相当复杂的方法,yield-returns IEnumerable<string>
,但是当我在Reflector中检查编译器输出时,我并不了解编译器生成的IEnumerator
实现的特定部分:
void IDisposable.Dispose()
{
switch (this.<>1__state)
{
case 1:
case 2:
case 3:
switch (this.<>1__state) // empty switch! why?!
{
}
break;
default:
return;
try // What?! AFTER return?!
{
}
finally // is the try-finally block anyhow relevant?
{
this.<>m__Finallya();
}
break;
}
this.<>m__Finally7();
}
我猜测(或希望)Reflector错放了外部switch
的右括号,并且它应该在return
后直接放置。 不过,我不明白为什么在案例3中有一个空开关,或者为什么在finally
块中调用m__Finallya
。 (正常运行和finally
块内部之间是否存在语义差异?除了CER之外,我的代码中没有。)
作为参考,这是IL:
.method private hidebysig newslot virtual final
instance void System.IDisposable.Dispose() cil managed
{
.override [mscorlib]System.IDisposable::Dispose
// Code size 69 (0x45)
.maxstack 2
.locals init ([0] int32 CS$0$0000,
[1] int32 CS$0$0001)
IL_0000: ldarg.0
IL_0001: ldfld int32 FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>1__state'
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: sub
IL_000a: switch (
IL_001c,
IL_001c,
IL_001c)
IL_001b: ret
IL_001c: ldarg.0
IL_001d: ldfld int32 FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>1__state'
IL_0022: stloc.1
IL_0023: ldloc.1
IL_0024: ldc.i4.2
IL_0025: sub
IL_0026: switch (
IL_0035,
IL_0035)
IL_0033: br.s IL_003e
.try
{
IL_0035: leave.s IL_003e
} // end .try
finally
{
IL_0037: ldarg.0
IL_0038: call instance void FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>m__Finallya'()
IL_003d: endfinally
} // end handler
IL_003e: ldarg.0
IL_003f: call instance void FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>m__Finally7'()
IL_0044: ret
} // end of method '<GetMissingMessages>d__0'::System.IDisposable.Dispose
你没有展示你的原始迭代器块是什么样的,但我对Reflector和编译器生成的代码的经验是它并不总是能够完全准确地反编译,因为编译器使用了一些没有等效的IL。 C#。
我有一篇关于迭代器块实现的文章可能对你有所帮助,但我不会太担心编译代码的样子。 在某些情况下,C#编译器几乎肯定会生成不必要的代码,因为这样可以使编译器更简单。 迭代器块必须非常难以正确(它可能变得非常复杂,最后是块和迭代器处理)所以我认为仅仅信任JIT来优化掉生成的代码中的开关/大小写等不必要的位是合理的。
这只是反射器努力跟上已生成的IL(因为迭代器块不必与“正常”C#相关,只要它们是有效的IL)。 特别是, ret
在finally
块之后。
我可以说C#编译器是愚蠢的,(它可能有点愚蠢)。 当运行时进行jitted时,这个代码看起来很可能非常不同(所有讨厌的垃圾都被省略)。
无论如何,你可能熟悉状态机吗? 当您使用C#(yield stuff)编写生成器时,您告诉编译器发出一个匿名类型,该类型将此生成器实现为状态机。 这是一个很好的正式方法,可以验证。 这可能是它看起来如此的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.