代码之家  ›  专栏  ›  技术社区  ›  Michael B

如何从动态方法中获取IL bytearray?

  •  8
  • Michael B  · 技术社区  · 15 年前

    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生成的代码?

    编辑2: 有人知道如何恢复方法中声明的局部变量吗?或者没有办法获取变量?

    4 回复  |  直到 15 年前
        1
  •  17
  •   Hans Passant    15 年前

    是的,不起作用,这个方法是由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>
            //...
    

        2
  •  1
  •   AbdelRaheim    14 年前

    ILReader听说应该有用。

    ILVisualizer 2010解决方案

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

        3
  •  0
  •   Michael B    15 年前

    根据汉斯·帕桑特的工作,我能够深入挖掘,似乎有一种方法,你应该调用,称为 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 这对我的工作有帮助。

        4
  •  0
  •   Community Mohan Dere    9 年前

    目前的解决方案并不能很好地解决.NET 4中的当前情况。你可以用任何一个 DynamicILInfo ILGenerator 创建动态方法,但此处列出的解决方案不适用 完全 .

    动态信息 生成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);
    }
    

    See this answer 有关更多帮助程序方法和DynamicMethod令牌解析问题的解决方案。