I've gone through and beat my head against the wall for a while now searched on various phrases and keywords but I cannot find anything close to an answer so i'm hoping someone here can shed some light.
Basically I'm working on diving pretty deep into manipulating, creating, and modifying Expression Trees in C# 4.0
I came across an odd anomaly I cannot make sense of
if I write something like this
Expression<Func<string,string>> InsertAString = (Insert) => "This " + (Insert == "" ? "" : Insert + " ") + "That";
When I get debug and look at the expression tree it looks similar to this
I can call
Console.WriteLine(InsertAString.Compile()("Is Something In-between"));
And I get out as I expect
"This is something In-between That"
Now if i try and rebuild that manually using the static methods of the Expression base class I run into an interesting issue. (I have broken down each step into its own Expression for debugging purposes)
ParameterExpression Insert = Expression.Parameter(typeof(object), "Insert");
ConstantExpression This = Expression.Constant("This ");
ConstantExpression That = Expression.Constant("That");
ConstantExpression Space = Expression.Constant(" ");
ConstantExpression NoCharacter = Expression.Constant("");
BinaryExpression InsertPlusSpace = Expression.Add(Insert,Space);
BinaryExpression InsertEqualsNoCharacter = Expression.Equal(Insert,NoCharacter);
ConditionalExpression InsertPlusSpaceOrNothing = Expression.IfThenElse(InsertEqualsNoCharacter,NoCharacter,InsertPlusSpace);
BinaryExpression ThisPlusInsertPlusSpaceOrNothing = Expression.Add(This,InsertPlusSpaceOrNothing);
BinaryExpression ThisPlusInsertPlusSpaceOrNothingPlusThat = Expression.Add(ThisPlusInsertPlusSpaceOrNothing, That);
Lambda Lambda = Expression.Lambda(ThisPlusInsertPlusSpaceOrNothingPlusThat, Middle);
Expression<Func<string,string>> InsertAString = Lambda as Expression<Func<string,string>>
That based on the values of the generated Expression tree above recreate the same basic expression tree as above (at least with the same "Look")
Everything steps through fine until you get to this line
BinaryExpression InsertPlusSpace = Expression.Add(Insert,Space);
The compiler throws an InvalidOperationException was unhandled
The binary operator Add is not defined for 'System.String' and 'System.String'
Now why is this?
Why when I let C# convert a Lambda into an Expression does it obviously use the Add NodeType, and the Types display show it is definitely using System.String yet when i try and do the same manually it will not let the code continue?
As a Final note I've even tried the following:
BinaryExpression InsertPlusSpace = Expression.MakeBinary( ExpressionType.Add,Insert,Space);
Same error.
I'm curious why it seems at least with what i have been able to find so far that string concatenation in expression trees works only if are not trying to build an expression tree manually that adds constants and variables of type System.String.
Thank you all in advance for the responses.
Check the documentation: the '+' operator is actually not defined in the String
class. I guess the compiler just knows it means "concatenate the strings", and it transforms it into a call to Concat
. So when you call Expression.Add
, you need to specify the method that implements the operation (in that case the String.Concat
method).
I decompiled the expression with Reflector, it gives the following result (reformatted):
ParameterExpression expression2;
Expression<Func<string, string>> expression =
Expression.Lambda<Func<string, string>>(
Expression.Add(
Expression.Add(
Expression.Constant("This ", typeof(string)),
Expression.Condition(
Expression.Equal(
expression2 = Expression.Parameter(typeof(string), "Insert"),
Expression.Constant("", typeof(string)),
false,
(MethodInfo) methodof(string.op_Equality)),
Expression.Constant("", typeof(string)),
Expression.Add(
expression2,
Expression.Constant(" ", typeof(string)),
(MethodInfo) methodof(string.Concat))),
(MethodInfo) methodof(string.Concat)),
Expression.Constant("That", typeof(string)),
(MethodInfo) methodof(string.Concat)),
new ParameterExpression[] { expression2 });
(Note that methodof
is not an actual operator, its just what Reflector shows for the ldtoken
IL instruction. In C# you have to retrieve the method using reflection.)
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