11

作为一个新奇事物,我试图看看 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)查看使用轻量级代码生成的代码生成的代码?

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

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

4

4 回答 4

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。

于 2010-11-10T17:20:24.797 回答
2

The ILReader here should work.

ILVisualizer 2010 Solution

于 2012-02-20T19:20:00.767 回答
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这对我的工作有帮助的问题。

于 2010-11-10T18:45:46.957 回答
0

当前的解决方案并不能很好地解决 .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 令牌解析问题的解决方案,请参阅此答案

于 2016-02-29T23:03:14.477 回答