Domanda

Ho scritto un metodo abbastanza complicato cedere i ritorni IEnumerable<string>, ma quando ho controllato l'output del compilatore in Reflector, non capivo una parte specifica per l'esecuzione generato dal compilatore di 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();
}

Sto indovinando (o sperare) che riflettore fuori luogo la coppia del switch esterna chiusura, e che dovrebbe essere direttamente dopo il return. Ancora, non capisco perché c'è un interruttore vuoto nel caso 3, o perché m__Finallya viene richiamato in un blocco finally. (C'è una differenza semantica tra l'esecuzione normalmente e all'interno di un blocco finally? Altro che CER, che non ho nel mio codice.)

Per avere un riferimento, ecco 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
È stato utile?

Soluzione

che è semplicemente riflettore lottando per tenere il passo con l'IL che è stato generato (dal blocchi iteratore non devono riguardare "normale" C #, purché siano validi IL). In particolare, il ret è dopo il blocco finally.

Altri suggerimenti

Non hai mostrato ciò che il vostro blocco iteratore originale sarà simile, ma la mia esperienza di riflettore e il codice generato dal compilatore è che non sempre riesce a decompilare tutto con precisione, perché il compilatore utilizza alcuni IL che non ha un equivalente in C #.

Ho un articolo su blocco iteratore implementazione che può aiutare un po ' , ma io non mi preoccuperei troppo di ciò che il codice compilato assomiglia. In alcuni casi il compilatore C # è quasi certamente genera codice non necessario per il fatto che che mantiene il compilatore più semplice. blocchi iteratore deve essere stato molto difficile da ottenere (si può ottenere molto complicato, con blocchi finally e lo smaltimento iterator) quindi penso che sia ragionevole fidarsi solo il JIT per ottimizzare via i bit inutili come l'opzione / caso nel codice generato.

ho potuto sostenere che il compilatore C # è stupido, (è probabilmente è un po 'stupido). E 'anche possibile che questo codice sembra molto diverso quando jitted dal run-time (tutto quel brutto spazzatura viene omesso).

In ogni caso, è forse familiarità con macchine a stati? Quando si scrive generatori in C # (roba resa) si dice al compilatore di emettere un tipo anonimo che implementa questo generatore come una macchina a stati. Questo è un bel approccio formale che è destinato ad essere verificabili. Questo è probabilmente i motivi per cui si guarda il modo in cui funziona.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top