实际上,有四个相关的问题:
1)为什么可以这样做?
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
但是不能这样做?
LambdaExpression decrementorExpression = (i => i - 1);
在第二种情况下,编译器会报告:&#34;无法将lambda表达式转换为&#39; System.Linq.Expressions.LambdaExpression&#39;因为它不是委托类型&#34;
2)TDelegate
和Expression<TDelegate>
之间的演员在哪里宣布?我想我记得过去见过它但现在似乎无法找到它。但我无法确定是否看到了它。
3)当我这样做时:
Expression<Func<int, int>> incrementExpression = (i => ++i);
编译器说,&#34;表达式树可能不包含赋值运算符。&#34; 为什么会这样?
4)然后如果我能做到这一点:
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
那为什么我不能this?
public Expression<Func<T>> ToExpression<T>(Func<T> func)
{
return func;
}
答案 0 :(得分:6)
你几乎已经找到了答案。
i => i + 1
不是Func<int, int>
。这是一个lambda表达式。 Lambda表达式可以转换为匹配的委托类型或匹配的表达式树类型。
如果将lambda表达式转换为委托类型,编译器会将其编译为具有指定效果的IL代码。
如果将lambda表达式转换为表达式树类型,则编译器会将其编译为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上{1}}。
存储在e
中的这些额外信息对于解释表达式树的库来说通常是必不可少的,因此从Func<int, int>
到Expression<Func<int, int>>
的隐式转换不会起作用:所需信息不再可用。
对于LambdaExpression decrementorExpression = (i => i - 1);
,这是无效的,因为编译器无法确定您是否需要Expression<Func<int, int>>
,Expression<Func<int, object>>
或Expression<MyFunc>
MyFunc
是您创建的自定义委托类型。
最后&#34;表达式树可能不包含赋值运算符&#34;,这主要是因为对于表达式树的预期用例,表达式包含赋值通常没有意义。但是,考虑到.NET表达式树能够表示赋值操作,这有点任意限制。
答案 1 :(得分:0)
以下是我脑海中的一些思想片段,它们有助于解决一些谜团。但我仍在等待一个完整的答案。
首先,i => i + 1
不是Func<int, int>
或Func
。后者是IL; Func是IL; TDelegate
是IL。 IL无法回复表达。
前者实际上是一种表达方式。它是lamda 表达式的一些文本表示。
现在,即使是这样,也必须在这种类型的文本类型i => i + 1
到Expression<TDelegate>
之间进行某些演员?
但我想没有,因为没有语法标记来表示文本i => i + 1
。必须有一些类在编译器DOM中表示这一点,但LINQ Expression API中没有任何内容可用于此类事情。所以编译器使用它自己的AST知道,&#34;哦,我刚刚遇到过这种文本。让我解析它并将其转换为Expression
。&#34;
但这就是我所拥有的,如果这是真的,那么只回答我问题的一部分。还在等待其余的谜题得到解决。