Во-первых, некоторые справочную информацию:Reflection.Emit.ILGenerator Обработка исключений «Оставить» Инструкция
творю компилятор для школьного проекта. Он уже работает, и я прилагаю много усилий для исправления ошибок и/или оптимизации. Я недавно столкнулся с проблемой с том, что я обнаружил, что объект ILGenerator генерирует дополнительный leave
инструкции при вызове любой из следующих методов членов:
BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()
Итак, вы начинаете попробовать заявление с вызовом BeginExceptionBlock()
, добавьте пару статей catch с BeginCatchBlock()
, возможно добавьте предложение finally с BeginFinallyBlock()
, а затем завершите защищенную область кода EndExceptionBlock()
.
Методы, которые я перечислял, автоматически генерируют командную инструкцию leave
с первой инструкцией после инструкции try. Я не хочу этого, по двум причинам. Один из них, потому что он всегда генерирует неоптимизированную инструкцию leave
, а не инструкцию leave.s
, даже если она разветвляется всего на два байта. И два, потому что вы не можете контролировать, где уходит инструкция на отпуск.
Итак, если вы хотите перейти в другое место в своем коде, вам нужно добавить локальную переменную, созданную компилятором, установить ее в зависимости от того, где вы хотите войти в оператор try, пусть EndExceptionBlock()
автоматически генерирует команду leave
, а затем сгенерируйте оператор switch ниже блока try. ИЛИ, вы можете просто испускать leave
или leave.s
инструкцию самостоятельно, перед вызовом одного из предыдущих методов, в результате чего в уродливом и недостижимых дополнительных 5 байт, например, так:
L_00ca: leave.s L_00e5
L_00cc: leave L_00d1
Оба этих варианта неприемлемы для меня. Есть ли способ предотвратить автоматическую генерацию команд leave
или какой-либо другой способ указать защищенные регионы, а не использовать эти методы (которые крайне раздражают и практически не документируют)?
EDIT Примечание: сам компилятор C# делает это, так что это не так, как будто есть веская причина, чтобы заставить его на нас. Например, если у вас есть .NET 4.5 бета, разобрать следующий код и проверить их выполнение: (блок исключения добавил внутренне)
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;
}
Спасибо за ответ. Я оставил его открытым, потому что я не был уверен, что решение, которое я нашел (MethodBuilder.SetMethodBody), действительно будет работать для меня - у него нет очень описательной документации. Еще раз спасибо! – aboveyou00