Сначала немного справочной информации:
Я делаю компилятор для школьного проекта.Это уже работает, и я прилагаю много усилий, чтобы исправить ошибку и / или оптимизировать ее.Недавно я столкнулся с проблемой, связанной с тем, что я обнаружил, что объект 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
инструкций или любой другой способ указать защищенные области вместо использования этих методов (которые чрезвычайно раздражают и практически не документированы)?
РЕДАКТИРОВАТЬ Примечание:Компилятор 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;
}