2009-08-01 12 views
11

Dopo aver sperimentato un blocco iteratore ho notato che il codice IL generato non è quello che mi aspettavo che fosse. Invece di un blocco try-finally viene generato un blocco try-fault, che non ho mai visto. Ho notato che il compilatore non mi permette di usare la parola chiave di errore in C# scritto a mano.blocco Iterator genera provare colpa in IL

C'è qualche differenza tra i 2?

codice C#:

static IEnumerable<string> ReadAllLines(string fileName) 
{ 
    using (var file = System.IO.File.OpenText(fileName)) 
    { 
     string s; 
     while ((s = file.ReadLine()) != null) 
     { 
      yield return s; 
     } 
    } 
} 

codice MSIL:

.method private hidebysig newslot virtual final instance bool MoveNext() cil managed 
{ 
    .override [mscorlib]System.Collections.IEnumerator::MoveNext 
    .maxstack 3 
    .locals init (
     [0] bool CS$1$0000, 
     [1] int32 CS$4$0001, 
     [2] string CS$0$0002, 
     [3] bool CS$4$0003) 
    L_0000: ldarg.0 

    // try body 

    L_008d: leave.s L_0097 
    L_008f: ldarg.0 
    L_0090: call instance void ConsoleApplication2.Program/<ReadAllLines>d__0::System.IDisposable.Dispose() 
    L_0095: nop 
    L_0096: endfinally 
    L_0097: nop 
    L_0098: ldloc.0 
    L_0099: ret 
    .try L_0000 to L_008f fault handler L_008f to L_0097 
} 

La linea interessante è l'ultima riga del IL, dove viene specificato un gestore degli errori, dove in un normale try-finally un infine viene specificato il gestore.

+1

Perché questo tag è specificamente con .net-4.0? Questo cambiamento è cambiato tra le versioni? –

risposta

8

Sì, un blocco finally viene eseguito sempre all'uscita telaio. Un blocco di errore viene eseguito solo se un'eccezione viene svolta oltre il fotogramma. Il blocco di errore in MoveNext mantiene la semantica di utilizzo per il caso di un'eccezione generata dal blocco try dell'iteratore ReadAllLines. Alcuni altri meccanismi devono essere in uso per preservare l'uso della semantica sull'uscita normale dall'iteratore.

+0

Quindi il Dispose in the fault viene chiamato solo quando si gestisce un'eccezione nella parte try. E il normale smaltimento è gestito dal metodo Dispose dell'IEnumerator generato. –