为什么我不能手动创建我的直接lambda生成的相同的表达式树 [英] Why can't I create the same Expression Tree manually that my straight lambda produces
问题描述
我已经经历了一段时间,现在我在墙上搜索了各种各样的短语和关键词,但是我找不到答案附近的任何东西,所以我希望这里的人能有所启发.
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.
基本上,我正在深入研究如何在C#4.0中操作,创建和修改表达式树
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
如果我写这样的东西
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
- F(NodeType = Lambda)
- 主体(NodeType =添加)
- 左(NodeType =添加)
- 左(NodeType =常数,值="This")
- 右(NodeType =有条件的)
- IfFalse(NodeType =添加)
- 左(NodeType =参数,名称=插入")
- 右(NodeType =常数,值=")
- F (NodeType = Lambda)
- Body (NodeType = Add)
- Left (NodeType = Add)
- Left (NodeType = Constant, Value = "This ")
- Right (NodeType = Conditional)
- IfFalse (NodeType = Add)
- Left (NodeType = Parameter, Name = "Insert")
- Right (NodeType = Constant, Value = " ")
- 左(NodeType =参数,名称=插入")
- 右(NodeType =常数,值=")
- 参数[0](NodeType =参数,名称=插入")
我可以打电话
Console.WriteLine(InsertAString.Compile()("Is Something In-between"));
我如期而至
这介于两者之间"
现在,如果我尝试使用Expression基类的静态方法手动重建它,则会遇到一个有趣的问题. (出于调试目的,我将每个步骤分解为自己的表达式)
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);
编译器抛出一个 原"InvalidOperationException"为 未处理
The compiler throws an InvalidOperationException was unhandled
未定义二进制运算符Add 对于'System.String'和 'System.String'
The binary operator Add is not defined for 'System.String' and 'System.String'
现在为什么?
为什么当我让C#将Lambda转换为Expression时,它显然使用了Add NodeType,而Types显示肯定是在使用System.String,但是当我尝试手动执行操作时,它不会让代码继续?
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);
相同的错误.
我很好奇为什么到目前为止看来,至少在不尝试手动构建添加System.String类型的常量和变量的表达式树的情况下,表达式树中的字符串连接才有效.
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.
提前谢谢大家的答复.
推荐答案
检查文档:实际上,在
String
类中未定义'+'运算符.我猜编译器只知道它的意思是连接字符串",并将其转换为对Concat
的调用.因此,在调用Expression.Add
时,您需要指定实现该操作的方法(在这种情况下为String.Concat
方法).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 toConcat
. So when you callExpression.Add
, you need to specify the method that implements the operation (in that case theString.Concat
method).我用Reflector反编译了表达式,它给出了以下结果(重新格式化):
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 });
(请注意,
methodof
不是实际的运算符,它只是Reflector为ldtoken
IL指令显示的内容.在C#中,您必须使用反射来检索该方法.)(Note that
methodof
is not an actual operator, its just what Reflector shows for theldtoken
IL instruction. In C# you have to retrieve the method using reflection.)这篇关于为什么我不能手动创建我的直接lambda生成的相同的表达式树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- IfFalse (NodeType = Add)
- Left (NodeType = Add)
- Body (NodeType = Add)
- IfFalse(NodeType =添加)
- 左(NodeType =添加)
- 主体(NodeType =添加)