作为一个新奇的东西,我试图看看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行,编译.Method.GetMethodBody()抛出异常。
EDIT2: 有谁知道如何恢复方法中声明的局部变量?或者没有GetVariables的方法吗?
答案 0 :(得分: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>
//...
在.NET 4.0上,您必须使用ilgen.GetType()。BaseType.GetField(...),因为IL生成器已更改,DynamicILGenerator,派生自ILGenerator。
答案 1 :(得分:1)
ILReader听说应该有用。
ILVisualizer 2010解决方案
http://blogs.msdn.com/b/haibo_luo/archive/2010/04/19/9998595.aspx
答案 2 :(得分:0)
根据Hans Passant的工作,我能够深入挖掘一下你应该调用的方法,称为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
这对我的工作有帮助的事情。
答案 3 :(得分:0)
目前的解决方案并不能很好地解决.NET 4中的当前情况。您可以使用DynamicILInfo
或ILGenerator
来创建动态方法,但此处列出的解决方案不适用于DynamicILInfo
动态方法 。
无论您使用生成IL的DynamicILInfo
方法还是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);
}
See this answer了解更多辅助方法和DynamicMethod令牌解析问题的解决方案。