【问题标题】:Building expression trees combining two functions to a composite function构建将两个函数组合为复合函数的表达式树
【发布时间】:2014-04-12 15:22:16
【问题描述】:

我得到了以下信息:

 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)  

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

【问题讨论】:

  • @Hammerstein 不会产生 OP 想要的结果。事实上,OP 要求的结果不包括 Func。
  • 有两个问题,可读版本以及如何将反编译的函数返回为表达式。我只是想帮助其中一个。
  • @Hammerstein OP 已经有表达式。
  • 你不想使用Expression.Compile。您想使用ExpressionVisitorExpressionParameter 替换为另一个Expression&lt;Func&gt;.Body 的主体,然后您想将其全部放入新的Expression.Lambda

标签: c# lambda tree expression composite


【解决方案1】:

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

不,至少不是一件容易的事。您必须解释 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) =&gt; cubed (XTCylinderVolume (r, h))之类的东西。

这与您所要求的不完全一样,但在功能上是等效的。

如果要实际扩展功能,那就有点难了……需要访问cubed的表达式树,将参数替换为XTCylinderVolume的body。

可以通过实现一个表达式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);
    }
}

然后你可以像这样使用它:

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

【讨论】:

  • thanx,看起来是一个非常相似的解决方案。 “ReplacementVisitor”是“替代”的一个不太优雅的词。
  • @GregorSchmitz,好吧,如果您愿意,“替代”比“替换”更优雅,但它访问者...
【解决方案2】:

您可以使用表达式访问者通过参数替换来做到这一点。这应该告诉你你需要知道的:http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees

【讨论】:

  • thanx 我认为这对函数组合有用。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-11
    • 1970-01-01
    相关资源
    最近更新 更多