¿Qué significa esto empadronador generado por el compilador?
-
23-08-2019 - |
Pregunta
Me escribió un método bastante complejo que el rendimiento de rendimientos IEnumerable<string>
, pero cuando inspeccionó la salida del compilador en el reflector, yo no entendía una parte específica de la aplicación generado por el compilador de 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();
}
supongo (o la esperanza) de que el reflector fuera de lugar la llave de cierre de la switch
exterior, y que debería ser directamente después de la return
. Aún así, no entiendo por qué hay un interruptor de vacío en el caso 3, o por qué m__Finallya
está siendo llamado en un bloque finally
. (¿Hay una diferencia semántica entre funcionando normalmente y dentro de un bloque finally
? Aparte de los CER, que no tengo en mi código.)
Para referencia, aquí es la 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
Solución
Esto es simplemente reflector luchando para mantenerse al día con la IL que se ha generado (ya que los bloques de iterador no tienen que relacionarse con "normal" C # siempre y cuando sean válidos IL). En particular, el ret
es después del bloque finally
.
Otros consejos
No ha mostrado lo que su bloque iterador original, parece, pero mi experiencia de reflector y el código generado por el compilador es que no siempre se las arregla para descomponer por completo con precisión, ya que el compilador utiliza algo de IL que no tiene un equivalente en C #.
Tengo un artículo sobre el bloque iterador aplicación que le puede ayudar un poco , pero yo no me preocuparía demasiado por lo que el código compilado se parece. En algunos casos, el compilador de C # es casi seguro que la generación de código innecesario sobre la base de que el compilador que mantiene simple. bloques de iterador deben haber sido muy difícil llegar a la derecha (que puede ser muy complicado, con bloques finally y la eliminación iterador), así que creo que es razonable sólo confía en el JIT para optimizar distancia los bits innecesarios como el modificador / caso en el código generado.
podría argumentar que el compilador de C # es estúpida, (que probablemente está es un poco estúpida). También es muy posible que este código se ve muy diferente cuando compilados JIT por el tiempo de ejecución (toda esa basura desagradable se omite).
En cualquier caso, que tal vez familiarizado con las máquinas de estado? Cuando se escribe generadores en C # (cosas de rendimiento) se indica al compilador para que emita un tipo anónimo que implementa este generador como una máquina de estados. Este es un enfoque formal agradable que está destinado a ser verificable. Eso es probablemente las razones por las que se ve la forma en que lo hace.