Как получить байтовый массив IL из DynamicMethod? - PullRequest
8 голосов
/ 10 ноября 2010

В качестве новшества я пытаюсь увидеть, насколько IL отличается от облегченного кода, сгенерированного во время выполнения, и кода, сгенерированного компилятором VS, поскольку я заметил, что код VS имеет тенденцию работать с другим профилем производительности. для таких вещей, как броски.

Итак, я написал следующий код:

Func<object,string> vs = x=>(string)x;
Expression<Func<object,string>> exp = x=>(string)x;
var compiled = exp.Compile(); 
Array.ForEach(vs.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine);
Array.ForEach(compiled.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine);

К сожалению, это вызывает исключение, поскольку GetMethodBody, по-видимому, является недопустимой операцией над кодом, сгенерированным деревьями выражений. Как я могу библиотечным способом (т.е. не с помощью внешнего инструмента, если у инструмента нет API) посмотреть на код, сгенерированный кодом с использованием облегченного codegen?

Редактировать: ошибка возникает в строке 5, compiled.Method.GetMethodBody () генерирует исключение.

Edit2: Кто-нибудь знает, как восстановить локальные переменные, объявленные в методе? Или нет способа получить GetVariables?

Ответы [ 4 ]

17 голосов
/ 10 ноября 2010

Да, не работает, метод генерируется Reflection.Emit.IL хранится в ILGenerator от MethodBuilder.Вы можете выкопать это, но вы должны быть довольно отчаянным.Отражение необходимо, чтобы добраться до внутренних и частных членов.Это работало в .NET 3.5SP1:

using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
...

        var mtype = compiled.Method.GetType();
        var fiOwner = mtype.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic);
        var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod;
        var ilgen = dynMethod.GetILGenerator();
        var fiBytes = ilgen.GetType().GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic);
        var fiLength = ilgen.GetType().GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic);
        byte[] il = fiBytes.GetValue(ilgen) as byte[];
        int cnt = (int)fiLength.GetValue(ilgen);
        // Dump <cnt> bytes from <il>
        //...

. В .NET 4.0 вам придется использовать ilgen.GetType (). BaseType.GetField (...), потому что генератор IL был изменен, DynamicILGeneratorполученный из ILGenerator.

1 голос
/ 20 февраля 2012

Слышит, что ILReader должен работать.

Решение ILVisualizer 2010

http://blogs.msdn.com/b/haibo_luo/archive/2010/04/19/9998595.aspx

0 голосов
/ 01 марта 2016

Текущие решения здесь не очень хорошо отражают текущую ситуацию в .NET 4.Вы можете использовать DynamicILInfo или ILGenerator для создания динамического метода, но перечисленные здесь решения не работают с DynamicILInfo динамическими методами вообще .

Используете ли выDynamicILInfo метод генерации IL или метод ILGenerator, байт-код IL заканчивается в DynamicMethod.m_resolver.m_code.Вам не нужно проверять оба метода, и это менее сложное решение.

Это версия, которую вы должны использовать:

public static byte[] GetILBytes(DynamicMethod dynamicMethod)
{
    var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod);
    if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized.");
    return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver);
}

См. Этот ответ длядополнительные вспомогательные методы и решение проблемы с разрешением токена DynamicMethod.

0 голосов
/ 10 ноября 2010

Основываясь на работе Ханса Пассанта, я смог немного глубже понять, что есть метод, который вы должны вызвать, который называется BakeByteArray, так что работает следующее:

var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod;
var ilgen =dynamicMethod.GetILGenerator();
byte[] il = ilgen.GetType().GetMethod("BakeByteArray", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(ilgen, null) as byte[];

Это, безусловно, помогает, но у меня до сих пор нет способа решить VariableInfo's, что поможет мне в моей работе.

...