作为一个新奇的东西,我试图看看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.