C# Lambda的二进制表达式

C# Lambda的二进制表达式,c#,lambda,expression-trees,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

有些人可能对此很熟悉。我有一个包装类
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

}
{。。。
Ex x=“x”;
exy=10.0;
exz=x+y;
LambdaExpression lambda=BuildLambda(z);
Func f=(Func)lambda.Compile();
//f(5)=15
}
但是如何正确地横切树并构建lambda(或委托)

LambdaExpression BuildLambda(表达式e)
{
恒压cex=e,表示恒压;
如果(cex!=null)
{
返回表达式.Lambda(cex);
}
ParameterExpression pex=e作为ParameterExpression;
如果(pex!=null)
{
Func f=(x)=>x;
表达体=f(pex);
返回表达式.Lambda(body,pex);
}
二进制表达式bex=e作为二进制表达式;
如果(bex!=null)
{
LambdaExpression left=GetLambda(bex.left);
LambdaExpression rght=GetLambda(bex.Right);
//现在怎么办?
}
返回null;
}
我尝试了几种方法将
BinaryExpression
bex转换成lambda,但到目前为止都没有成功。我想要一些建议和建议。请注意,该操作的操作数可能是其他表达式对象,并且仅在树的叶子处,它们将是
ParameterExpression
ConstantExpression


谢谢。

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

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.
}
在每个步骤中,从
Ex
实例中“解包”
表达式,应用
表达式。*
方法,并将结果包装到新的
Ex
实例中

最后,您只需从最后的
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);
exx=newex(表达式参数(typeof(double),“x”);
exy=新的Ex(表达式常数(10.0,typeof(double));
exz=x+y;
表达结果=
Lambda(z.表达式,x.表达式);

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

Expression<Func<double, double>> result = x => x + 10.0;
表达式结果=x=>x+10.0;

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

如果您的表达式都来自一个公共类,请在Gamma等中查找“访问者”模式。这甚至是他们使用的示例。

创建树不是问题。我的
Ex x=“x”
工作正常。使用
Ex x=“x”解决了代理的创建问题;exy=10.0;exz=x+y;表达式lambda=Expression.lambda((表达式)z,(参数表达式)(表达式)x);Func f3=(Func)lambda.Compile();双重结果=f3(5);//结果=15
非常感谢。诀窍就是这样做,让编译器了解细节。你有没有一个参考/示例/教程专门介绍如何从代码构建表达式树,然后编译为委托?下一步是将其扩展到方法/函数调用,以及上面所做的简单算术。@jalexiou:我认为您的Ex类可能是多余的——您似乎复制了很多已经存在的函数。如果要动态定义表达式树,可以使用expression.*方法。如果您想静态定义表达式树,C#编译器可以为您生成它们。如果只需要一个静态lambda表达式,则根本不需要表达式树。你想做什么?
System.Linq.Expressions.ExpressionVisitor
是一个内部类,我无法从中继承。@jalexiou:System.Linq.Expressions.ExpressionVisitor已在.NET 4.0中公开。
Expression<Func<double, double>> result = x => x + 10.0;