Чтобы понять, что вы делаете, я предлагаю вам сделать как можно более минимальный пример.
ilGen.Emit(OpCodes.Ldstr, "a");
ilGen.BeginExceptionBlock();
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();
ilGen.Emit(OpCodes.Pop);
ilGen.Emit(OpCodes.Ret);
После этого, вы можете использовать AssemblyBuilder
сбросить данный код в исполняемый файл. Если это будет сделано, ildasm
покажет, что было создано.
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldstr "a"
.try
{
IL_0005: leave IL_000f
} // end .try
catch [mscorlib]System.Exception
{
IL_000a: leave IL_000f
} // end handler
IL_000f: pop
IL_0010: ret
Как вы можете видеть, мы достигнем к leave
инструкции, которая перескакивает на pop
. Вы можете Google о leave
, в котором говорится, что:
Инструкция отпуска аналогична инструкции бр, но он может быть используется для выхода попробовать, фильтр, или поймать блок, тогда как в обычной ветви инструкции могут используется только в таком блоке для передачи управления внутри него. Команда «Оставшийся» освобождает стопку оценки и гарантирует, что будут выполнены соответствующие окружающие окончательные блоки.
Однако почему тогда не работает следующая работа?
ilGen.Emit(OpCodes.Ldstr, "a");
ilGen.BeginExceptionBlock();
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();
//ilGen.Emit(OpCodes.Pop);
ilGen.Emit(OpCodes.Ret);
Я подозреваю, что это может быть не «физический предел», а проблема проверки. Бежим peverify ourapp.exe
и посмотрим, что мы получаем:
[IL]: Error: [C:\temp\test.exe : Program::Main][offset 0x00000005] Attempt to en
ter a try block with nonempty stack.
1 Error(s) Verifying C:\temp\test.exe
На данный момент, вы можете быть как, ват? С небольшим количеством поисковых запросов вы можете найти код ошибки 0x801318A9. Быстрое сканирование через источники SSCLI2.0:
case ReaderBaseNS::RGN_TRY:
// Entering a try region, the evaluation stack is required to be empty.
if (!m_readerStack->empty()) {
BADCODE(MVER_E_TRY_N_EMPTY_STACK);
}
break;
Теперь, это здорово, но если вы вызывающие, вы можете спросить, почему стек оценки должны быть пустыми?
Для этого вы, вероятно, захотите взглянуть на ECMA C# and Common Language Infrastructure Standards. Я подозреваю, что вы можете найти причину из PartitionIII CIL.pdf
Я подозреваю, что это так (что стек оценки должен быть пустым, прежде чем вводить новый кадр исключения), но я не могу найти официальную ссылку прямо сейчас. –