Reputation: 24017
Is there a way to convert a MethodBody (or other Reflection technique) into a System.Linq.Expressions.Expression tree?
Upvotes: 5
Views: 807
Reputation: 91
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:
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));
}
}
Upvotes: 2
Reputation: 84755
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.
Upvotes: 1