2012-03-09 2 views
10

Во-первых, некоторые справочную информацию: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; 
} 

ответ

7

Насколько я могу судить, вы не можете сделать это в .NET 4.0. Единственный способ создать тело метода без с использованием ILGenerator - это использовать MethodBuilder.CreateMethodBody, но это не позволяет вам устанавливать информацию об обработке исключений. И ILGenerator заставляет команду leave, о которой вы спрашиваете.

Однако, если .NET 4.5 является вариантом для вас (это похоже), взгляните на MethodBuilder.SetMethodBody. Это позволяет вам самостоятельно создавать IL, но все равно передавать информацию об обработке исключений. Вы можете обернуть это в свой собственный собственный класс ILGenerator, используя методы Emit, принимающие аргумент OpCode, и чтение OpCode.Size и OpCode.Value для получения соответствующих байтов.

И, конечно же, всегда есть Mono.Cecil, но это, вероятно, требует более обширных изменений в коде, который вы уже написали.

Редактировать: you appear to have already figured this out yourself, но вы оставили этот вопрос открытым. Вы можете публиковать ответы на свои вопросы и принимать их, если вы сами это поняли. Это позволило бы мне знать, что я не должен был тратить время на поиски, и это позволило бы другим людям с тем же вопросом знать, что делать.

+0

Спасибо за ответ. Я оставил его открытым, потому что я не был уверен, что решение, которое я нашел (MethodBuilder.SetMethodBody), действительно будет работать для меня - у него нет очень описательной документации. Еще раз спасибо! – aboveyou00

 Смежные вопросы

  • Нет связанных вопросов^_^