gpt4 book ai didi

c# - 为什么我不能手动创建与我的直接 lambda 生成的相同的表达式树

转载 作者:太空狗 更新时间:2023-10-29 18:33:16 24 4
gpt4 key购买 nike

我已经把头撞在墙上一段时间了,现在搜索了各种短语和关键字,但我找不到任何接近答案的东西,所以我希望这里的人能给出一些启示。

基本上,我正在深入研究在 C# 4.0 中操作、创建和修改表达式树

我遇到了一个我无法理解的奇怪异常

如果我这样写

Expression<Func<string,string>> InsertAString = (Insert) => "This " + (Insert == "" ? "" : Insert + " ") + "That";

当我进行调试并查看表达式树时,它看起来与此类似

  • F(节点类型 = Lambda)
    • 正文(节点类型 = 添加)
      • 左(节点类型 = 添加)
        • 左(NodeType = 常量,Value = "This ")
        • 正确(NodeType = 条件)
          • IfFalse(节点类型 = 添加)
            • 左(NodeType = 参数,名称 = "插入")
            • 正确(NodeType = 常量,值 = "")
          • IfTrue (NodeType = Constant, Value = "")
          • 测试(节点类型 = 相等)
            • 左(NodeType = 参数,名称 = "插入")
            • 对(NodeType = Constant,Value = "")
      • 正确(NodeType = Constant,Value = "That")
    • 参数(计数 = 1)
      • 参数[0](节点类型=参数,名称=“插入”)

我可以打电话

Console.WriteLine(InsertAString.Compile()("Is Something In-between"));

然后我如我所愿的离开了

“这是介于两者之间的东西”

现在,如果我尝试使用 Expression 基类的静态方法手动重建它,我会遇到一个有趣的问题。 (出于调试目的,我将每个步骤分解为自己的表达式)

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

根据上面生成的表达式树的值重新创建与上面相同的基本表达式树(至少具有相同的“外观”)

一切都很好,直到你到达这一行

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'

这是为什么?

为什么当我让 C# 将 Lambda 转换为表达式时,它显然使用了 Add NodeType,并且类型显示显示它肯定在使用 System.String,但是当我尝试手动执行相同操作时,它不会让代码继续?

作为最后的说明,我什至尝试了以下方法:

BinaryExpression InsertPlusSpace = Expression.MakeBinary( ExpressionType.Add,Insert,Space);

同样的错误。

我很好奇为什么看起来至少到目前为止我已经能够找到表达式树中的字符串连接仅在不尝试手动构建表达式树以添加 System.String 类型的常量和变量时才有效.

提前感谢大家的回复。

最佳答案

查看文档:“+”运算符实际上未在 String 类中定义。我猜编译器只知道它的意思是“连接字符串”,并将其转换为对 Concat 的调用。因此,当您调用 Expression.Add 时,您需要指定实现该操作的方法(在这种情况下为 String.Concat 方法)。

我用 Reflector 反编译了表达式,它给出了以下结果(重新格式化):

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# 中,您必须使用反射来检索方法。)

关于c# - 为什么我不能手动创建与我的直接 lambda 生成的相同的表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3858247/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com