为什么我不能手动创建我的直接lambda生成的相同的表达式树 [英] Why can't I create the same Expression Tree manually that my straight lambda produces

查看:55
本文介绍了为什么我不能手动创建我的直接lambda生成的相同的表达式树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经经历了一段时间,现在我在墙上搜索了各种各样的短语和关键词,但是我找不到答案附近的任何东西,所以我希望这里的人能有所启发.

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 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).

                      我用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 the ldtoken IL instruction. In C# you have to retrieve the method using reflection.)

                      这篇关于为什么我不能手动创建我的直接lambda生成的相同的表达式树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆