2010-09-01 1 views
2

Есть ли способ конвертировать MethodBody (или другую технику отражения) в дерево System.Linq.Expressions.Expression?Преобразование методаBody в дерево выражений

+0

Почему вы конкретно хотите использовать 'MethodBody'? – ChaosPandion

+0

Есть ли что-то еще? Я упомянул об этом, потому что там вы получаете массив байтов IL. –

+0

Да, есть что-то еще. Вам также понадобится 'MethodBase', так как здесь вы получаете доступ к сигнатуре метода (параметры и тип возвращаемого значения); вам понадобится это для создания экземпляра ['LambdaExpression'] (http://msdn.microsoft.com/en-us/library/system.linq.expressions.lambdaexpression.aspx). – stakx

ответ

0

Нет, нет.

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

+0

Ну, это был рефлектор, который заставил меня задаться вопросом, возможно ли это. –

+0

@ Крис: Если вы переписываете рефлектор, да. – SLaks

1

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

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

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

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

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

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

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

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

1

Это действительно возможно, см DelegateDecompiler:

https://github.com/hazzik/DelegateDecompiler

ПРИМЕЧАНИЕ: Я не связан с этим проектом

Edit

Здесь основная подход, который принимает проект:

  1. Получить MethodInfo для метода, который требуется преобразовать
  2. Используйте methodInfo.GetMethodBody, чтобы получить объект MethodBody. Это содержит, среди прочего, MSIL и информация о аргументах и ​​местных
  3. Пройти через инструкцию, изучить опкоды и построить соответствующие выражения
  4. Tie это все вместе и вернуть оптимизированное Expression

Вот фрагмент кода из проекта, который декомпилирует тело метода:

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

Спасибо за отзыв, ребята. В этом случае я не уверен, что включать, поскольку проект, который я связывал в целом, должен отвечать. Может быть, подытожим подход? – user3647737