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
¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top