这可能是一些人所熟悉的。我有一个包装类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,到目前为止所有这些都是不成功的。我想要一些建议和指示。请注意,操作的操作数可能是其他表达式对象,并且仅在树的叶子处,它们将是ParameterExpression
或ConstantExpression
。
感谢。
答案 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等人的“访客”模式。这甚至是他们使用的例子。