将 MethodBody 转换为表达式树

发布于 2024-09-16 20:49:22 字数 75 浏览 9 评论 0原文

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

Is there a way to convert a MethodBody (or other Reflection technique) into a System.Linq.Expressions.Expression tree?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

霞映澄塘 2024-09-23 20:49:22

这确实是可能的,请参阅 DelegateDecompiler:

https://github.com/hazzik/DelegateDecompiler

注意:我是隶属于此项目

编辑

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

  1. 获取要转换的方法的 MethodInfo
  2. 使用 methodInfo.GetMethodBody 获取 MethodBody 对象。这包含,
    除其他外,MSIL 以及有关参数和局部变量的信息
  3. 仔细阅读说明,检查操作码,并构建适当的表达式
  4. 将它们组合在一起并返回优化的表达式

以下是反编译方法体的项目中的代码片段:

 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));
        }
    }

It is indeed possible, see DelegateDecompiler:

https://github.com/hazzik/DelegateDecompiler

NOTE: I am not affiliated with this project

Edit

Here is the basic approach that the project takes:

  1. Get MethodInfo for the method you want to convert
  2. Use methodInfo.GetMethodBody to get a MethodBody object. This contains,
    among other things, the MSIL and info on arguments and locals
  3. Go through the instructions, examine the opcodes, and build the appropriate Expressions
  4. Tie it all together and return an optimized Expression

Here is a code snippet from the project that decompiles a method body:

 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));
        }
    }
虚拟世界 2024-09-23 20:49:22

不,没有。

您基本上是在要求 Reflector 的稍微简单的版本。

No, there isn't.

You're basically asking for a somewhat simpler version of Reflector.

℉絮湮 2024-09-23 20:49:22

是的,有可能……但据我所知,尚未实现。

如果有人知道将方法反编译为表达式树的库,请告诉我,或编辑上述语句。

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

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

在一些值得注意的情况下,这会变得特别棘手:

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

  • 您是否会尝试识别某些高级构造,例如 C# using 块,并尝试为其构建一个(自定义)表达式树节点?请记住,C# using 分解为相当于 try...finally { someObj.Dispose(); } 在编译期间,因此如果您通过 方法体的 CIL 指令异常处理子句

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

Yes, it is possible... but it hasn't been done yet, as far as I know.

If anyone does know of a library that de-compiles methods to expression trees, please let me know, or edit the above statement.

The most difficult part of what you would have to do is write a CIL de-compiler. That is, you would need to translate the fairly low-level CIL instructions (which conceptually target a stack machine) into much higher-level expressions.

Tools such as Redgate's Reflector or Telerik's JustDecompile do just that, but instead of building expression trees, they display source code; you could say they go one step further, since expression trees are basically still language-agnostic.

Some notable cases where this would get especially tricky:

  • You would have to deal with cases of CIL instructions for which no pre-defined Expression tree node exists; let's say, tail.call, or cpblk (I'm guessing a little here). That is, you'd have to create custom expression tree node types; having them compiled back into an executable method when you .Compile() the expression tree might be an issue, because the expression tree compiler tries to break down custom nodes into standard nodes. If that is not possible, then you cannot compile the expression tree any more, you could only inspect it.

  • Would you try to recognise certain high-level constructs, such as a C# using block, and try to build a (custom) expression tree node for it? Remember that C# using breaks down to the equivalent of try…finally { someObj.Dispose(); } during compilation, so that is what you might see instead of using if you reflected over the method body's CIL instructions and exception handling clauses.

    Thus, in general, expect that you need to be able to "recognise" certain code patterns and summarise them into a higher-level concept.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文