Pergunta

Eu escrevi um método bastante complexo que rendimento retornos IEnumerable<string>, mas quando eu inspecionou a saída do compilador no refletor, eu não entendi uma parte específica da implementação gerado pelo 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();
}

Eu estou supondo (ou esperando) que refletor perdido a chave de fechamento do switch exterior, e que ele deve ser, imediatamente após a return. Ainda assim, eu não entendo porque é que há um interruptor vazio no caso 3, ou por m__Finallya está sendo chamado em um bloco finally. (Existe uma diferença semântica entre funcionando normalmente e dentro de um bloco finally? Além CER de que eu não tenho no meu código.)

Para referência, aqui é a 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
Foi útil?

Solução

Isso é simplesmente refletor lutando para manter-se com o IL que foi gerado (desde iterador blocos não têm de se relacionar com "normal" C #, enquanto eles estão IL válido). Em particular, o ret é após o bloco finally.

Outras dicas

Você não tem mostrado o que a sua aparência bloco iterador originais como, mas minha experiência de refletor e um código gerado pelo compilador é que nem sempre conseguem decompor totalmente com precisão, porque o compilador usa algum IL que não tem um equivalente em C #.

Eu tenho um href="http://csharpindepth.com/Articles/Chapter11/StreamingAndIterators.aspx" artigo sobre iterador bloco implementação que pode ajudá-lo um pouco , mas eu não me preocuparia muito com o que os olhares código compilado como. Em alguns casos, o compilador C # é quase certamente gerar o código desnecessário, alegando que que mantém o compilador simples. Iterator blocos deve ter sido muito complicado para obter direito (ele pode ficar muito complicado, com finally blocos e iterator disposição) Então eu acho que é razoável apenas confiar no JIT para otimizar afastado os bits desnecessários como o switch / case no seu código gerado.

Eu poderia argumentar que o compilador C # é estúpido, (que provavelmente é um pouco estúpido). Também é bem possível que isso parece código muito diferentes quando JITted pelo run-time (todo esse lixo desagradável se omitido).

De qualquer forma, você talvez familiarizado com máquinas de estado? Quando você escreve geradores em C # (coisas de rendimento) você diz o compilador para emitir um tipo anônimo que implementa este gerador como uma máquina de estado. Esta é uma abordagem formal agradável que se destina a ser verificáveis. Isso é provavelmente as razões pelas quais a aparência que ele faz.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top