Reputation: 29274
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.
Upvotes: 5
Views: 5966
Reputation: 217401
You can create the Expression Tree as you call the conversion operators:
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.
}
At each step, you "unpack" the Expression
from the Ex
instance(s), apply the Expression.*
method, and wrap the result in a new Ex
instance.
At the end, all you have to do is extract the Expression
from the final Ex
instance:
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);
Note that the C# compiler provides the feature to create an Expression Tree for you:
Expression<Func<double, double>> result = x => x + 10.0;
creates exactly the same Expression Tree as the code above.
Upvotes: 6
Reputation: 894
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.
Upvotes: 0