For the very first time I am exploring expression trees. I have a few basic doubts.
So essentially , an expression takes only a lambda expression . Ans then we can Compile() the lambda expression to MSIL code which in turn returns a generic delegate. We can invoke the returned delegate as it is . Is my understanding correct ?
If it is here is what I am trying to achieve: ((10*5)+(9/4))
BinaryExpression b1 = Expression.MakeBinary(ExpressionType.Multiply, Expression.Constant(10), Expression.Constant(5));//(10*5)
BinaryExpression b2 = Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(9), Expression.Constant(4));//(9/4)
BinaryExpression b4 = Expression.MakeBinary(ExpressionType.Add, b1, b2);//((10*5)+(9/4))
So at this point we have made the lambda expression body
. Now to turn it to a full lambda expression
we need to call
Console.WriteLine(Expression.Lambda<Func<int, int>>(b4).Compile());
I am not getting this part . And this does not work also .
Why this Func<int,int>
?
Is it like the inner expressions will take only int as param and the entire expression will return an int?
Obviously this does not work. How the generated lambda looks like ?
I am getting the entire picture? How to make this work?
Expression.Lambda<Func<int, int>>(b4).Compile()
Func<int,int>
is a signature for lambdas that take a single int
parameter, and return an int
. Your lambda has a different signature.
Obviously this does not work.
Your lambda does not take any parameters, so you need Func<int>
instead.
How the generated lambda looks like?
Generated lambda is a callable object. If you would like to evaluate the expression that you get back, cast and call it, like this:
var compiledLambda = (Func<int>)Expression.Lambda<Func<int>>(b4).Compile();
Console.WriteLine(compiledLambda());
// ^^
The above prints 52
, as expected.
Demo 1.
If you would like to make a Func<int,int>
, add a parameter to your expression, e.g. make it (p*5)+(9/4)
where p
is an int
parameter:
ParameterExpression p = Expression.Parameter(typeof(int));
BinaryExpression b1 = Expression.MakeBinary(ExpressionType.Multiply, p, Expression.Constant(5));//(p*5)
BinaryExpression b2 = Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(9), Expression.Constant(4));//(9/4)
BinaryExpression b4 = Expression.MakeBinary(ExpressionType.Add, b1, b2);
var compiledLambda = (Func<int,int>)Expression.Lambda<Func<int,int>>(b4, new[] {p}).Compile();
Console.WriteLine(compiledLambda(10)); // Prints 52
Console.WriteLine(compiledLambda(8)); // Prints 42
Demo 2.
You can create your lambda expression like that:
LambdaExpression lb = Expression.Lambda(b4);
You can then compile this expression to a delegate:
Delegate dlg = lb.Compile();
And cast this delegate to a Func<int>
:
Func<int> f = (Func<int>)dlg;
And you can use this as usual:
Console.WriteLine(f()); // 52
The generic way works, too. Why do you use Func<int,int>
? Your expression takes no input and returns a single int
:
Func<int> f = Expression.Lambda<Func<int>>(b4);
The generic argument leads to a LambdaExpression
with a Compile
method that returns a Func<int>
instead of a Delegate
that you'd need to cast again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With