如何从DynamicMethod获取IL bytearray?

Mic*_*l B 9 c# dynamicmethod

作为一个新奇的东西,我试图看看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);
Run Code Online (Sandbox Code Playgroud)

不幸的是,这会引发异常,因为GetMethodBody显然是对表达式树生成的代码的非法操作.我怎样才能以库的方式(即不使用外部工具,除非工具有API)查看代码使用轻量级codegen生成的代码?

编辑:错误发生在第5行,编译.Method.GetMethodBody()抛出异常.

Edit2:有谁知道如何恢复方法中声明的局部变量?或者没有办法GetVariables?

Han*_*ant 17

是的,不起作用,该方法由Reflection.Emit生成.IL存储在MethodBuilder的ILGenerator中.你可以把它挖出来,但你必须非常绝望.需要反思内部和私人成员.这适用于.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>
        //...
Run Code Online (Sandbox Code Playgroud)

在.NET 4.0上,您必须使用ilgen.GetType().BaseType.GetField(...),因为IL生成器已更改,DynamicILGenerator,派生自ILGenerator.