1

I got the following:

 Expression<Func<double, double, double>> XTCylinderVolume =
                (r, h) => 3.14  * r * r * h;
 Expression<Func<double, double>> cubed =    (V) => V  * V * V ;

I can combine them to building a composite function call it fgCompiled.

 var cubedC = cubed.Compile();
 Func<double, double, double> fgComplied = (r, h) => cubedC(XTCylinderVolume.Compile()(r, h));

  fgCompiled(2,1)  
 //answer = 1981.385..;

How can I get an Expression fg that is not compiled so that fg.ToString() would read like

=> (3.14 * r * r * h ) * ( 3.14 * r * r * h ) * (3.14 * r * r * h)  

or hopefully neater but that would be a start.
Is there a way to decompiled a compiled function back to an expression?

Gregor
  • 358
  • 2
  • 7
  • For decompiling a compiled function, See: http://stackoverflow.com/questions/9377635/create-expression-from-func – tbddeveloper Apr 13 '14 at 10:38
  • @Hammerstein will not produce the result that the OP wants. In fact the OP is asking for a result that does not include a Func. – Aron Apr 13 '14 at 10:39
  • There are two questions, the readable version and how to get a decompiled function back to an expression. I was just trying to help with one of them. – tbddeveloper Apr 13 '14 at 10:42
  • @Hammerstein OP already has the Expression. – Aron Apr 13 '14 at 10:42
  • You don't want to use `Expression.Compile`. You want to use `ExpressionVisitor` to replace `ExpressionParameter` with the body of the other `Expression.Body` then you want to put that all into a new `Expression.Lambda` – Aron Apr 13 '14 at 10:44

3 Answers3

3

Is there a way to decompiled a compiled function back to an expression?

No, at least not an easy one. You would have to interprete the IL code and translate it back.

You can combine your two functions like this:

 var pr = Expression.Parameter(typeof(double), "r");
 var ph = Expression.Parameter(typeof(double), "h");
 Expression<Func<double, double, double>> fgCompiled =
    Expression.Lambda<Func<double, double, double>>(
        Expression.Invoke(
            cubed,
            Expression.Invoke(
                XTCylinderVolume,
                pr, ph)),
        pr, ph);

Which would give you something like (r, h) => cubed (XTCylinderVolume (r, h)).

It's not exactly what you asked, but it's functionally equivalent.

If you want to actually expand the function, it's a bit harder... You need to visit the expression tree of cubed and replace the parameter with the body of XTCylinderVolume.

It can be done by implementing an expression visitor:

class ParameterReplacementVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _paramToReplace;
    private readonly Expression _replacementExpression;
    public ParameterReplacementVisitor(ParameterExpression paramToReplace, Expression replacementExpression)
    {
        _paramToReplace = paramToReplace;
        _replacementExpression = replacementExpression;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == _paramToReplace)
            return _replacementExpression;
        return base.VisitParameter(node);
    }
}

Which you can then use like this:

var visitor = new ParameterReplacementVisitor(cubed.Parameters[0], XTCylinderVolume.Body);
var expandedBody = visitor.Visit(cubed.Body);

var fgCompiled = 
    Expression.Lambda<Func<double, double, double>>(
        expandedBody,
        XTCylinderVolume.Parameters);
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
2

You can do this with parameter substitution using an expression visitor. This should tell you what you need to know: http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees

satnhak
  • 9,407
  • 5
  • 63
  • 81
0

Using Thomas Levesque's visitor implementation, single-parameter lambda composition can be generalized.

public static Expression<Func<TSource, TFinal>>
  CompositeExpression<TSource, TInner, TFinal>
  (
    this Expression<Func<TInner, TFinal>> outerlambda,
    Expression<Func<TSource, TInner>> innerlambda)
{
  var visitor = new ParameterReplacementVisitor(outerlambda.Parameters[0], innerlambda.Body);
  var expandedOuter = visitor.Visit(outerlambda.Body);

  var composite =
    Expression.Lambda<Func<TSource, TFinal>>(
      expandedOuter,
      innerlambda.Parameters);
  return composite;
}
Marc L.
  • 3,296
  • 1
  • 32
  • 42