Во-первых, некоторая справочная информация:
Я делаю компилятор для школьного проекта. Он уже работает, и я прилагаю много усилий для исправления ошибок и/или оптимизации. Я недавно столкнулся с проблемой в том, что я обнаружил, что объект ILGenerator генерирует дополнительную команду leave
при вызове любого из следующих методов-членов:
BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()
Итак, вы запускаете оператор try с вызовом 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
или какой-либо другой способ указать защищенные области, а не использовать эти методы (которые крайне раздражают и практически недокументированы)?
ИЗМЕНИТЬ Примечание: сам компилятор С# делает это, так что это не так, как если бы у нас была веская причина заставить его действовать. Например, если у вас есть бета-версия .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;
}