Как использовать Mono.Cecil для анализа инструкций IL из массива байтов

Я динамически компилирую исходный код с помощью CodeDOM, теперь я хочу работать с сгенерированным IL-кодом определенного метода с помощью Cecil, CodeDOM предоставляет мне IL-код метода в виде массива байтов, есть ли способ создать MethodBody, (или просто массив Mono.Cecil.Cil.Instruction) из этого байт-кода без сохранения сборки и перехода оттуда?


person Robert J.    schedule 24.04.2013    source источник
comment
Как сгенерировать IL с помощью CodeDom без создания сборки?   -  person Simon Mourier    schedule 24.04.2013
comment
Ну, я только что понял, что он все равно создаст временный файл за кулисами, даже если вы установите для CompilerParameters.GenerateInMemory значение true. Однако, конечно, я собираю сборку, мой вопрос был о работе с результатами в памяти.   -  person Robert J.    schedule 24.04.2013
comment
Cecil полагается на свой собственный загрузчик сборок, поэтому он не может использовать свойство CompilerResults.CompiledAssembly, но это не должно быть проблемой, поскольку, как вы выяснили, CodeDom всегда создает реальный файл за кулисами события с GenerateInMemory=true (это потому что CSC всегда работает вне процесса, в отличие от чего-то вроде Roslyn stackoverflow. com/questions/7852926/microsoft-roslyn-vs-codedom). Итак, я считаю, что вы можете просто указать Сесилу загрузить сборку из CompilerResults.PathToAssembly.   -  person Simon Mourier    schedule 24.04.2013
comment
Очевидно, я не могу использовать CompilerResults.CompiledAssembly, но имеющийся у меня байт-код должен быть понятен Сесилу. Но да, сейчас я работаю с временными файлами, и это работает, просто это не так элегантно, как если бы все это делалось в памяти. Однако, поскольку это вообще невозможно с CodeDom, я думаю, что все в порядке. Спасибо за ваши комментарии!   -  person Robert J.    schedule 24.04.2013


Ответы (1)


В Cecil есть функция, которая анализирует двоичный IL. Он находится в классе CodeReader в пространство имен Mono.Cecil.Cil. Метод ReadCode делает больше или меньше, чем вы хотите. Но класс устроен таким образом, что вы не можете просто передать byte[]. Как правило, вам необходимо разрешать токены метаданных, например. для вызовов методов. CodeReader для этого требуется конструктор via MetadataReader, а MetadataReader, в свою очередь, требует ModuleDefinition.


Есть альтернатива, если вы не используете Cecil. Используйте SDILReader:

// get the method that you want to extract the IL from
MethodInfo methodInfo = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);

Globals.LoadOpCodes();

// doesn't work on DynamicMethod
MethodBodyReader reader = new MethodBodyReader(methodInfo);
List<ILInstruction> instructions = reader.instructions;
string code = reader.GetBodyCode();

Другой альтернативой является ILReader из ILVisualizer 2010 Solution. .

DynamicMethod dynamicMethod = new DynamicMethod("HelloWorld", typeof(void), new Type[] { }, typeof(Program), false);

ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldstr, "hello, world");       
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilGenerator.Emit(OpCodes.Ret);

MethodBodyInfo methodBodyInfo = MethodBodyInfo.Create(dynamicMethod);
string ilCode = string.Join(Environment.NewLine, methodBodyInfo.Instructions);

// get the method that you want to extract the IL from
MethodInfo methodInfo = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);
MethodBodyInfo methodBodyInfo2 = MethodBodyInfo.Create(methodInfo);
string ilCode2 = string.Join(Environment.NewLine, methodBodyInfo2.Instructions);
person riQQ    schedule 23.11.2020