代码之家  ›  专栏  ›  技术社区  ›  John Alexiou

二元表达式到lambda

  •  4
  • John Alexiou  · 技术社区  · 14 年前

    有些人可能对此很熟悉。我有一个包装类 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 贝克斯变成了一个lambda,到目前为止,一切都还没有成功。我想要一些建议和建议。请注意,该操作的操作数可能是其他表达式对象,并且仅在树的叶处,它们可能是 ParameterExpression ConstantExpression .

    谢谢。

    2 回复  |  直到 14 年前
        1
  •  6
  •   dtb    14 年前

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

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

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

        2
  •  0
  •   Zachary Vance    14 年前

    如果您的表达式都来自一个公共类,那么在gamma等中查找“visitor”模式。这甚至是他们使用的例子。