构建将两个函数组合到复合函数的表达式树

时间:2014-04-12 15:22:16

标签: c# lambda tree expression composite

我得到了以下内容:

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

我可以将它们组合成一个复合函数,称之为fgCompiled

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

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

如何获得未编译的表达式fg,以便fg.ToString()读取为

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

或希望更整洁,但这将是一个开始 有没有办法将已编译的函数反编译回表达式?

3 个答案:

答案 0 :(得分:3)

  

有没有办法将已编译的函数反编译回表达式?

不,至少不是一件容易的事。您必须解释IL代码并将其翻译回来。

您可以将这两个功能组合在一起:

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

这会给你类似(r, h) => cubed (XTCylinderVolume (r, h))的内容。

这不完全是你所问的,但它在功能上是等同的。

如果你想真正扩展这个功能,那就更难了......你需要访问cubed的表达式树,并用XTCylinderVolume的主体替换参数。

可以通过实现表达式访问者来完成:

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

然后你可以这样使用:

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

答案 1 :(得分:2)

您可以使用表达式访问者进行参数替换。这应该告诉您需要知道的内容:http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees

答案 2 :(得分:0)

使用Thomas Levesque的访客实现,可以推广单参数lambda组合。

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