In primo luogo, alcune informazioni di fondo:Reflection.Emit.ILGenerator Gestione delle eccezioni "Leave" istruzioni
Sto creando un compilatore per un progetto scolastico. Funziona già e sto impiegando un sacco di sforzi per correggere i bug e/o ottimizzarli. Recentemente ho incontrato un problema con è che ho scoperto che l'oggetto ILGenerator genera un leave
di istruzioni in più quando si chiama uno dei seguenti metodi membri:
BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()
Quindi, si avvia un'istruzione try con una chiamata a BeginExceptionBlock()
, aggiungere un paio di clausole di catch con BeginCatchBlock()
, eventualmente aggiungere una clausola finally con BeginFinallyBlock()
e quindi terminare la regione di codice protetta con EndExceptionBlock()
.
I metodi che ho elencato generano automaticamente un ramo di istruzioni leave
alla prima istruzione dopo l'istruzione try. Non voglio questi, per due ragioni. Uno, perché genera sempre un'istruzione leave
non ottimizzata, piuttosto che un'istruzione leave.s
, anche quando si diramano solo due byte di distanza. E due, perché non puoi controllare dove va l'istruzione di congedo.
Quindi, se si desidera eseguire il diramazione in un'altra posizione nel codice, è necessario aggiungere una variabile locale generata dal compilatore, impostarla in base a dove si desidera andare all'interno dell'istruzione try, lasciare generare automaticamente EndExceptionBlock()
l'istruzione leave
e quindi generare un'istruzione switch sotto il blocco try. Oppure, si potrebbe semplicemente emettere un leave
o leave.s
istruzioni da soli, prima di chiamare uno dei metodi precedenti, con conseguente in un brutto e irraggiungibili in più 5 byte, in questo modo:
L_00ca: leave.s L_00e5
L_00cc: leave L_00d1
Entrambe queste opzioni sono per me inaccettabile. C'è un modo per evitare che sia la generazione automatica di leave
istruzioni, oppure qualsiasi altro modo per specificare le regioni protette piuttosto che utilizzare questi metodi (che sono estremamente fastidioso e praticamente privi di documenti)?
EDIT Nota: il compilatore C# si fa questo, quindi non è come se ci fosse un buon motivo per forzare su di noi. Ad esempio, se si dispone di .NET 4.5 beta, smontare il seguente codice e verificare la loro attuazione: (blocco di eccezione aggiunto internamente)
public static async Task<bool> TestAsync(int ms)
{
var local = ms/1000;
Console.WriteLine("In async call, before await " + local.ToString() + "-second delay.");
await System.Threading.Tasks.Task.Delay(ms);
Console.WriteLine("In async call, after await " + local.ToString() + "-second delay.");
Console.WriteLine();
Console.WriteLine("Press any key to continue.");
Console.ReadKey(false);
return true;
}
Grazie per la risposta. L'ho lasciato aperto perché non ero sicuro che la soluzione che ho trovato (MethodBuilder.SetMethodBody) avrebbe effettivamente funzionato per me - non ha una documentazione molto descrittiva. Grazie ancora! – aboveyou00