二进制表达式到 Lambda
这对一些人来说可能很熟悉。我有一个包装类 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
。
谢谢。
This may be familiar to some. I have a wrapper class Ex
that wraps an expression tree with a bunch of implicit conversions and operators. Here is simplified version
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));
}
}
So here is what I want to do:
{ ...
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
}
But how to I transverse the tree propely and build my lambda's (or delegates)
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;
}
I have tried several things to get to convert the BinaryExpression
bex into a lambda, and all have been unsucessful up to now. I'd like some suggestions and pointers. Note that the operands of the operation might be other expression objects and only at the leafs of the tree they will either be ParameterExpression
or ConstantExpression
.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以在调用转换运算符时创建表达式树:
在每一步中,您从
Ex
实例中“解压”Expression
,应用Expression.*
方法,并将结果包装在新的Ex
实例中。最后,您所要做的就是从最终的Ex 实例中提取
Expression
:请注意,C# 编译器提供了为您创建表达式树的功能:
创建与上面的代码完全相同的表达式树。
You can create the Expression Tree as you call the conversion operators:
At each step, you "unpack" the
Expression
from theEx
instance(s), apply theExpression.*
method, and wrap the result in a newEx
instance.At the end, all you have to do is extract the
Expression
from the finalEx
instance:Note that the C# compiler provides the feature to create an Expression Tree for you:
creates exactly the same Expression Tree as the code above.
如果您的表达式都派生自一个公共类,请在 Gamma 等中查找“Visitor”模式。这甚至是他们使用的例子。
If your expressions all derive from a common class, look up the "Visitor" pattern in Gamma, et al. This is even the example they use.