Получение значения из вершины стека IL с использованием IL Emit - PullRequest
1 голос
/ 14 января 2020

У меня есть LocalBuilder, который по сути является массивом. Я могу использовать его в IL просто отлично, и я могу загрузить его, используя OpCodes.Ldlen. Мне было просто интересно, есть ли способ получить длину от вершины стека до некоторой фактической переменной. Я ищу что-то вроде

int lengthVariable = 0;

IL.Emit(OpCodes.Ldloc, arr);
IL.Emit(OpCodes.Ldlen);
IL.Emit(??????, lengthVariable);

Я хочу получить эту переменную, чтобы я мог запустить все oop в зависимости от длины массива. Я знаю, что могу создать al oop в IL, но я подумал, что было бы намного удобнее, если бы это было возможно.

Редактировать: Я пытаюсь сделать здесь 1001 * 1009. *

Вызовите внешний метод (который возвращает массив). Выполните некоторые действия со всеми элементами этого массива. В настоящее время я делаю это, имея две копии массива (IL и не-IL). Используя копию без IL, я получаю длину, а затем выполняю действие n раз.

Проблема в том, что мне теперь приходится дважды вызывать внешний метод. Я надеялся, что смогу получить длину из массива IL, чтобы я мог напрямую * l oop, не вызывая внешний метод дважды. Я знаю, что могу написать для l oop в IL, но я как бы избегал написания ветвящихся операторов IL.

1 Ответ

1 голос
/ 14 января 2020

Вы не можете заполнить свой локальный lengthVariable таким образом - он работает в совершенно отдельной области видимости / стека. Однако вы можете изменить свой метод (DynamicMethod или MethodBuilder) на , вернуть его, затем создать делегат для вашего нового метода как Func<int> и вызвать его.

Тогда ваша последняя строка будет IL.Emit(Opcodes.Ret);, чтобы вернуть единственное значение в локальном стеке. В качестве альтернативы вы можете сохранить значение в поле экземпляра или состояния c с Opcodes.Stfld или Opcodes.Stsfld.


После обсуждения в комментариях кажется, что замечание

Я знаю, что могу написать для l oop в IL, но я как бы избегал написания разветвленных операторов IL.

в вопросе может быть преодолимым; foreach на самом деле не так уж и сложен - последний IL, который вам нужен, можно получить , декомпилируя существующий код , что оставляет единственный действительно хитрый бит обработка меток для фактических целей ветвления - но это просто означает вызов .DefineLabel() до объявления их - вы можете использовать их в качестве целей, прежде чем вы узнаете, куда они будут прыгать - и .MarkLabel() для поместите их (только один раз). Это не совсем direct IL (он использует уровень абстракции), но вы можете увидеть, что этот подход используется здесь - в частности, обратите внимание, что он использует DefineLabel() раньше времени и отмечает места назначения позже на MarkLabel.

...