Po pierwsze, niektóre informacje tła:Reflection.Emit.ILGenerator Obsługa wyjątków „Leave” Instrukcja
Robię kompilatora dla szkolnego projektu. To już działa, a ja wkładam wiele wysiłku, aby naprawić i/lub zoptymalizować go. I niedawno napotkasz problem z jest to, że odkryłem, że obiekt ILGenerator generuje dodatkowy leave
dyspozycję podczas wywołania jednej z następujących metod członkowskich:
BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()
Więc rozpocząć oświadczenie spróbować z wywołaniem BeginExceptionBlock()
, dodaj kilka klauzul catch z BeginCatchBlock()
, ewentualnie dodaj klauzulę finally z BeginFinallyBlock()
, a następnie zakończ region chronionego kodu wartością EndExceptionBlock()
.
Wymienione przeze mnie metody automatycznie generują rozkaz instrukcji leave
do pierwszej instrukcji po instrukcji try. Nie chcę tych z dwóch powodów. Jeden, ponieważ zawsze generuje niezoptymalizowaną instrukcję, a nie instrukcję leave.s
, nawet jeśli rozgałęzia się tylko o dwa bajty. I dwa, ponieważ nie możesz kontrolować, gdzie idzie instrukcja urlopowa.
Tak więc, jeśli chcesz rozgałęzić się do innej lokalizacji w kodzie, musisz dodać zmienną lokalną generowaną przez kompilator, ustawić ją w zależności od tego, gdzie chcesz wejść do instrukcji try, pozwolić EndExceptionBlock()
automatycznie wygenerować instrukcja leave
, a następnie wygeneruj instrukcję przełączania poniżej bloku try. OR, można po prostu emitują leave
lub leave.s
instrukcji samodzielnie, przed skontaktowaniem się z jedną z powyższych metod, powodując brzydkie i nieosiągalny dodatkowych 5 bajtach, tak jak poniżej:
L_00ca: leave.s L_00e5
L_00cc: leave L_00d1
Obie te opcje są nie do przyjęcia dla mnie. Czy jest jakiś sposób, aby zapobiec automatycznemu generowaniu instrukcji leave
, czy też w inny sposób określić chronione regiony zamiast używać tych metod (które są wyjątkowo irytujące i praktycznie nieudokumentowane)?
EDYTOWANIE Uwaga: kompilator języka C# sam to robi, więc nie jest tak, że istnieje dobry powód, aby go na nas zmusić. Na przykład, jeśli masz .NET 4.5 beta, demontować poniższy kod i sprawdzić ich realizację: (blok wyjątek dodany wewnętrznie)
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;
}
Dzięki za odpowiedź. Zostawiłem to otwarte, ponieważ nie byłem pewien, czy rozwiązanie, które znalazłem (MethodBuilder.SetMethodBody) faktycznie będzie działać dla mnie - nie ma bardzo opisowej dokumentacji. Dzięki jeszcze raz! – aboveyou00