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

本文关键字:组合 复合函数 表达式 函数 两个 构建 | 更新日期: 2023-09-27 17:58:12

我得到了以下内容:

 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)  

或者希望更整洁,但这将是一个开始
有没有一种方法可以将编译后的函数反编译回表达式?

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

有没有一种方法可以将编译后的函数反编译回表达式?

不,至少不容易。您必须解释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);

您可以使用表达式访问者通过参数替换来实现这一点。这应该会告诉您需要了解的内容:http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees

使用Thomas Levsque的访问者实现,可以推广单参数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;
}