使用多个参数手动创建ExpressionTree

时间:2014-05-28 19:19:17

标签: c# expression-trees

我正在创建树状结构,允许用户定义数学运算。用户选择功能(比如Add),并且在节点的叶子中(至少两个,但可以更多)用户可以指定参数(值或其他功能)。我认为使用表达式是一个好主意,但似乎表达式只支持二进制操作。我想知道是否有一些方法来创建具有两个以上参数的Add函数表达式。例如,如果我写:

Expression<Func<double, double, double, double>> e = (x, y, z) => x + y + z;

我得到树:[(x + y)+ z],所以显然有某种解析器。

如果我无法使用,我可能会编写一些逻辑来手动创建子树。或者也许有更好的方法?任何帮助将不胜感激。

以下是我的简单节点类:

abstract class Node
{
    public abstract void PrepareExpression();
    public Expression  Expr { get; set; }
    public string Name { get; set; }
    public IList<Node> InnerNodes { get; set; }

    protected Node()
    {
        InnerNodes = new List<Node>();
    }
}

class AddFunction : Node
{
    public AddFunction()
    {
        Name = String.Format("Sum_{0}", Guid.NewGuid());
    }

    public override void PrepareExpression()
    {
        var exprParams = new List<ParameterExpression>(InnerNodes.Count);
        foreach (var node in InnerNodes)
        {
            node.PrepareExpression();
        }
        var binaryExpression = Expression.AddChecked(InnerNodes[0].Expr, InnerNodes[1].Expr);
        Expr = binaryExpression;
    }
}

class ValueArgument : Node
{
    public double Value { get; set; }

    public ValueArgument(double value)
    {
        Name = String.Format("Val_{0}", Guid.NewGuid());
        Value = value;
    }

    public override void PrepareExpression()
    {
        var constantExpression = Expression.Constant(Value, typeof(double));
        Expr = constantExpression;
    }
}

评估整棵树:

rootNode.PrepareExpression();
var expr = Expression.Lambda<Func<double>>(rootNode.Expr);
var exprCom = expr.Compile();
var result = exprCom.Invoke();

2 个答案:

答案 0 :(得分:2)

您的示例中的表达式是二进制的,这就是您所需要的。只需多次应用它们。您自己提供的示例:

x + y + z = (x + y) + z

对应于二元运算符的两个应用程序,即两个二进制表达式:

Add( Add(x, y), z)

这里有两个主要观察结果:

  • 应用Add的结果本身就是一个表达式,因此它可以是另一个Add操作的操作数
  • 没有三元加法操作:&#34; 1 + 2 + 3&#34;。后者只是(1 + 2)+ 3的缩写。

答案 1 :(得分:0)

您是否希望将字符串解析为表达式?如果是这样,不要重新发明轮子。查看Dijkstra的Shunting Yard algorithm