将MethodBody转换为表达式树

时间:2010-09-01 14:54:26

标签: .net-4.0 linq-expressions

有没有办法将MethodBody(或其他反射技术)转换为System.Linq.Expressions.Expression树?

3 个答案:

答案 0 :(得分:1)

是的,有可能......但据我所知,它还没有完成。

  

如果有人 知道了一个将方法解组成表达式树的库,请告诉我,或者编辑上面的语句。

您需要做的最困难的部分是编写CIL反编译器。也就是说,您需要将相当低级别的CIL指令(概念上以堆栈计算机为目标)转换为更高级别的表达式。

Redgate的Reflector或Telerik的JustDecompile等工具就是这样做的,但它们不是构建表达式树,而是显示源代码;你可以说他们更进了一步,因为表达树基本上仍然与语言无关。

一些值得注意的案例,其中特别棘手:

  • 您必须处理没有预定义Expression树节点的CIL指令的情况;比方说,tail.callcpblk(我在这里猜一点)。也就是说,您必须创建自定义表达式树节点类型;当.Compile()表达式树可能成为问题时将它们编译回可执行方法,因为表达式树编译器试图将自定义节点分解为标准节点。如果那是不可能的,那么你就不能再编译表达式树了,你只能检查它。

  • 您是否会尝试识别某些高级构造(例如C#using块)并尝试为其构建(自定义)表达式树节点?请记住,C#using在编译期间会分解为try…finally { someObj.Dispose(); },因此如果您反映在method body's CIL instructions和{{3}上,那么您可能会看到而不是using }}

    因此,一般来说,期望您需要能够“识别”某些代码模式并将它们概括为更高级别的概念。

答案 1 :(得分:1)

确实可以,请参阅DelegateDecompiler:

https://github.com/hazzik/DelegateDecompiler

注意:我隶属于此项目

编辑

以下是项目采用的基本方法:

  1. 获取要转换的方法的MethodInfo
  2. 使用methodInfo.GetMethodBody获取MethodBody对象。这包含, 其中包括MSIL和关于参数和本地的信息
  3. 阅读说明,检查操作码,并构建适当的表达式
  4. 将它们组合在一起并返回优化的表达式
  5. 以下是项目中反编译方法体的代码片段:

     public class MethodBodyDecompiler
        {
            readonly IList<Address> args;
            readonly VariableInfo[] locals;
            readonly MethodInfo method;
    
            public MethodBodyDecompiler(MethodInfo method)
            {
                this.method = method;
                var parameters = method.GetParameters();
                if (method.IsStatic)
                    args = parameters
                        .Select(p => (Address) Expression.Parameter(p.ParameterType, p.Name))
                        .ToList();
                else
                    args = new[] {(Address) Expression.Parameter(method.DeclaringType, "this")}
                        .Union(parameters.Select(p => (Address) Expression.Parameter(p.ParameterType, p.Name)))
                        .ToList();
    
                var body = method.GetMethodBody();
                var addresses = new VariableInfo[body.LocalVariables.Count];
                for (int i = 0; i < addresses.Length; i++)
                {
                    addresses[i] = new VariableInfo(body.LocalVariables[i].LocalType);
                }
                locals = addresses.ToArray();
            }
    
            public LambdaExpression Decompile()
            {
                var instructions = method.GetInstructions();
                var ex = Processor.Process(locals, args, instructions.First(), method.ReturnType);
                return Expression.Lambda(new OptimizeExpressionVisitor().Visit(ex), args.Select(x => (ParameterExpression) x.Expression));
            }
        }
    

答案 2 :(得分:0)

不,没有。

你基本上要求更简单的版本Reflector