Конвертировать MethodBody в дерево выражений - PullRequest
2 голосов
/ 01 сентября 2010

Есть ли способ преобразовать MethodBody (или другую технику Reflection) в дерево System.Linq.Expressions.Expression?

Ответы [ 3 ]

1 голос
/ 16 августа 2012

Да, это возможно ... но, насколько я знаю, это еще не сделано.

Если кто-либо делает знать библиотеку, которая декомпилирует методы для деревьев выражений, пожалуйста, дайте мне знать, или отредактируйте вышеприведенный оператор.

Самая трудная часть того, что вам придется делатьэто написать CIL декомпилятор.То есть вам нужно было бы перевести довольно низкоуровневые инструкции CIL (которые концептуально нацелены на стековую машину) в гораздо более высокоуровневые выражения.

Инструменты, такие как Reflector Redgate или Telerik JustDecompile делает именно это, но вместо построения деревьев выражений они отображают исходный код;Вы могли бы сказать, что они идут на один шаг дальше, поскольку деревья выражений в основном все еще не зависят от языка.

Некоторые примечательные случаи, когда это может быть особенно сложным:

  • Вы бы получилииметь дело со случаями инструкций CIL, для которых не существует заранее определенного узла дерева Expression;скажем, tail.call или cpblk (я думаю, здесь немного).То есть вам нужно создать пользовательские типы узлов дерева выражений;их компиляция обратно в исполняемый метод при .Compile() дереве выражений может быть проблемой, поскольку компилятор дерева выражений пытается разбить пользовательские узлы на стандартные узлы.Если это невозможно, вы больше не можете скомпилировать дерево выражений, вы можете только проверить его.

  • Попытаетесь ли вы распознать некоторые высокоуровневые конструкции, такие как блок C # using, и попытаться построить для него (пользовательский) узел дерева выражений?Помните, что C # using разбивается до эквивалента try…finally { someObj.Dispose(); } во время компиляции, так что это то, что вы могли бы увидеть вместо using, если вы размышляли над инструкциями CIL и тела метода Обработка предложений .

    Таким образом, в общем, ожидайте, что вы должны иметь возможность «распознавать» определенные шаблоны кода и обобщать их в концепцию более высокого уровня.

1 голос
/ 09 июня 2015

Это действительно возможно, см. 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));
        }
    }
0 голосов
/ 01 сентября 2010

Нет, нет.

В основном вы запрашиваете несколько более простую версию Reflector .

...