BinaryExpression到Lambda

时间:2010-08-20 19:55:11

标签: c# lambda expression-trees

这可能是一些人所熟悉的。我有一个包装类Ex,它用一堆隐式转换和运算符包装表达式树。这是简化版

public class Ex 
{
    Expression expr;

    public Ex(Expression expr)
    {
        this.expr = expr;
    }
    public static implicit operator Expression(Ex rhs) { return rhs.expr; }
    public static implicit operator Ex(double value) 
    { return new Ex(Expression.Constant(value, typeof(double))); }
    public static implicit operator Ex(string x) 
    { return new Ex(Expression.Parameter(typeof(double), x)); }
    public static Ex operator +(Ex left, Ex right)
    {
        return new Ex(Expression.Add(left, right));
    }
    public static Ex operator -(Ex rhs)
    {
        return new Ex(Expression.Negate(rhs));
    }
    public static Ex operator -(Ex left, Ex right)
    {
        return new Ex(Expression.Subtract(left, right));
    }
    public static Ex operator *(Ex left, Ex right)
    {
        return new Ex(Expression.Multiply(left, right));
    }
    public static Ex operator /(Ex left, Ex right)
    {
        return new Ex(Expression.Divide(left, right));
    }
}

所以这就是我想要做的事情:

{ ...
    Ex x = "x";
    Ex y = 10.0;
    Ex z = x + y;

    LambdaExpression lambda = BuildLambda(z);
    Func<double,double> f = (Func<double,double>)lambda.Compile();

    // f(5) = 15

}

但是我如何正确地横向树并建立我的lambda(或代表)

    LambdaExpression BuildLambda(Expression e)
    {
        ConstantExpression cex = e as ConstantExpression;
        if(cex != null)
        {
            return Expression.Lambda<Func<double>>( cex );
        }
        ParameterExpression pex = e as ParameterExpression;
        if (pex != null)
        {
            Func<Expression, Expression> f = (x) => x;
            Expression body = f(pex);
            return Expression.Lambda<Func<double, double>>( body , pex);
        }
        BinaryExpression bex = e as BinaryExpression;
        if (bex != null)
        {
            LambdaExpression left = GetLambda(bex.Left);
            LambdaExpression rght = GetLambda(bex.Right);
   // Now what?
        }
        return null;
    }

我已经尝试了几件事来将BinaryExpression bex转换为lambda,到目前为止所有这些都是不成功的。我想要一些建议和指示。请注意,操作的操作数可能是其他表达式对象,并且仅在树的叶子处,它们将是ParameterExpressionConstantExpression

感谢。

2 个答案:

答案 0 :(得分:6)

您可以在调用转换运算符时创建表达式树:

public class Ex
{
    private readonly Expression expr;

    public Ex(Expression expr)
    {
        this.expr= expr;
    }

    public Expression Expression
    {
        get { return this.expr; }
    }

    public static Ex operator +(Ex left, Ex right)
    {
        return new Ex(Expression.Add(left.expr, right.expr));
    }                                       ↑           ↑

    // etc.
}

在每一步中,您从Expression实例“解包”Ex,应用Expression.*方法,并将结果包装到新的Ex中实例

最后,您所要做的就是从最终的Expression实例中提取Ex

Ex x = new Ex(Expression.Parameter(typeof(double), "x"));
Ex y = new Ex(Expression.Constant(10.0, typeof(double)));
Ex z = x + y;

Expression<Func<double, double>> result =
    Expression.Lambda<Func<double, double>>(z.Expression, x.Expression);

请注意,C#编译器提供了为您创建表达式树的功能:

Expression<Func<double, double>> result = x => x + 10.0;

创建与上面代码完全相同的表达式树。

答案 1 :(得分:0)

如果你的表达式都来自一个普通的类,请查看Gamma等人的“访客”模式。这甚至是他们使用的例子。