【问题标题】:Where is the implicit cast from TDelegate to Expression<TDelegate> declared?从 TDelegate 到 Expression<TDelegate> 的隐式转换在哪里声明?
【发布时间】:2015-01-02 07:34:46
【问题描述】:

其实相关的四个问题:

1) 为什么可以这样做?

Expression<Func<int, int>> incrementorExpression = (i => i + 1);

但不能做到这一点?

LambdaExpression decrementorExpression = (i => i - 1);

在第二种情况下,编译器报告如下:“无法将 lambda 表达式转换为类型 'System.Linq.Expressions.LambdaExpression',因为它不是委托类型”

2) TDelegateExpression&lt;TDelegate&gt; 之间的演员表在哪里声明?我想我记得在过去见过它,但现在似乎找不到它。但我不确定我是否看到它。

3) 当我这样做时:

Expression<Func<int, int>> incrementExpression = (i => ++i);

编译器说,“表达式树可能不包含赋值运算符。”为什么会这样?

4) 如果我能做到的话:

Expression<Func<int, int>> incrementorExpression = (i => i + 1);

那我为什么不能this呢?

public Expression<Func<T>> ToExpression<T>(Func<T> func)
{
  return func;
}

【问题讨论】:

  • 我不认为 3 属于:i =&gt; (i = i + 1) 并不真正代表表达式...
  • ++i 仅表示return (i + 1)。这并不意味着i = i + 1i += 1 不是一个表达式,因为它意味着 i = i + 1,而是一个语句。
  • 这对我来说是个新闻……据我所知,++i{ i = i + 1; return i;}……
  • 你是对的。谢谢。 :-) 我的错。有了这个,你刚刚回答了我列表中的 (3) 个。

标签: c# .net linq lambda linq-expressions


【解决方案1】:

你几乎已经找到答案了。

i =&gt; i + 1 不是Func&lt;int, int&gt;。它是一个 lambda 表达式。 Lambda 表达式可以转换为匹配的委托类型,或匹配的表达式树类型。

如果将 lambda 表达式转换为委托类型,编译器会将其编译为具有指定效果的 IL 代码。

如果将 lambda 表达式转换为表达式树类型,编译器会将其编译为 IL,IL 会生成一个表达式树,该树表示您在 lambda 表达式中编写的内容。表达式树是供库稍后解析的,因此表达式树必须与您编写的代码紧密匹配。

Func<int, int> f = i => i + 1; // okay, creates delegate.
Expression<Func<int, int>> e = i => i + 1; // okay, creates expression tree.

无法从f 检索到有关它执行的操作的信息。从它的委托类型可知,它接受一个int 并返回一个int,但除此之外,它是一个黑盒子。输入一个数字,然后输出一个数字,但您不再知道如何操作。

另一方面,e 存储1 被添加到名为i 的参数的事实,甚至1 出现在+ 的RHS 上。

存储在e 中的这些额外信息对于那些解释表达式树的库来说通常是必不可少的,因此从Func&lt;int, int&gt;Expression&lt;Func&lt;int, int&gt;&gt; 的隐式转换是行不通的:所需的信息不再可用。

对于LambdaExpression decrementorExpression = (i =&gt; i - 1);,这是无效的,因为编译器无法确定您是否需要Expression&lt;Func&lt;int, int&gt;&gt;Expression&lt;Func&lt;int, object&gt;&gt;Expression&lt;MyFunc&gt;,其中MyFunc 是自定义委托类型你创造的。

最后是“表达式树可能不包含赋值运算符”,这主要是因为对于表达式树的预期用例,表达式包含赋值通常没有意义。不过,考虑到 .NET 表达式树能够表示赋值操作,这有点武断。

【讨论】:

    【解决方案2】:

    以下是我脑海中的一些想法片段,它们有助于解开一些谜团。但我仍在等待一个完整的答案。

    首先,i =&gt; i + 1 不是 Func&lt;int, int&gt;Func 任何东西。后者是IL;函数是 IL; TDelegate 是 IL。没有办法从 IL 回到表达式。

    前者实际上是一个表达式。它是 lamda 表达式的一些文本表示。

    现在,即使是这样,从 i =&gt; i + 1 这种类型的文本类型的东西到 Expression&lt;TDelegate&gt; 一定有一些转换?

    但我想没有,因为没有语法标记来表示文本 i =&gt; i + 1。在编译器 DOM 中必须有一些类来表示这个,但 LINQ 表达式 API 中没有任何东西可以处理这种事情。所以编译器使用自己的 AST 来知道,“哦,我刚刚遇到了这样的一段文本。让我解析它并把它变成一个Expression。”

    但这就是我所拥有的,如果它是真的,那只是回答我问题的一部分。仍在等待解决剩下的难题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-12
      • 1970-01-01
      • 2019-02-26
      • 1970-01-01
      • 1970-01-01
      • 2012-03-07
      相关资源
      最近更新 更多