从 TDelegate 到 Expression<TDelegate> 的隐式转换在哪里声明?
Where is the implicit cast from TDelegate to Expression<TDelegate> declared?
其实有四个相关的问题:
1) 为什么可以这样做?
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
但是做不到吗?
LambdaExpression decrementorExpression = (i => i - 1);
在第二种情况下,编译器报告如下:"Cannot convert lambda expression to type 'System.Linq.Expressions.LambdaExpression' because it is not a delegate type"
2) TDelegate
和 Expression<TDelegate>
之间的转换在哪里声明?我想我记得以前见过它,但现在似乎找不到了。但是我不能确定我是否看到了。
3) 当我这样做时:
Expression<Func<int, int>> incrementExpression = (i => ++i);
编译器说,"An expression tree may not contain an assignment operator."为什么会这样?
4) 如果我能做到:
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
那为什么我做不到this?
public Expression<Func<T>> ToExpression<T>(Func<T> func)
{
return func;
}
这是我脑海中的一些想法碎片,它们有助于解开一些谜团。但我还在等待一个完整的答案。
首先,i => i + 1
不是 Func<int, int>
或 Func
任何东西。后者是 IL; Func 是 IL; TDelegate
是 IL。无法从 IL 返回表达式。
前者其实是一个表达式。它是 lamda 表达式.
的一些文本表示
现在,即使是这样,从这种类型的文本类型的东西 i => i + 1
到 Expression<TDelegate>
?
也一定有一些转换
但我猜没有,因为没有语法标记来表示文本 i => i + 1
。在编译器 DOM 中必须有一些 class 表示此内容,但在 LINQ 表达式 API 中没有任何内容用于此类事情。所以编译器使用它自己的 AST 来知道,"Oh, I just met with this sort of a piece of text. Let me parse it and turn it into an Expression
."
但这就是我的全部,如果是真的,那只能回答我问题的一部分。还在等待剩下的谜题被解开。
您几乎已经找到答案了。
i => i + 1
不是 Func<int, int>
。它是一个 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
和 returns 一个 int
,但除此之外,它是一个黑盒子。你输入一个数字,然后你得到一个数字,但你不再知道如何。
另一方面,e
存储了将 1
添加到名为 i
的参数的事实,甚至 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
是您创建的自定义委托类型。
最后是"An expression tree may not contain an assignment operator",这主要是因为对于表达式树的预期用例,表达式包含赋值通常没有意义。不过,考虑到 .NET 表达式树能够表示赋值操作,这是一个有点武断的限制。
其实有四个相关的问题:
1) 为什么可以这样做?
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
但是做不到吗?
LambdaExpression decrementorExpression = (i => i - 1);
在第二种情况下,编译器报告如下:"Cannot convert lambda expression to type 'System.Linq.Expressions.LambdaExpression' because it is not a delegate type"
2) TDelegate
和 Expression<TDelegate>
之间的转换在哪里声明?我想我记得以前见过它,但现在似乎找不到了。但是我不能确定我是否看到了。
3) 当我这样做时:
Expression<Func<int, int>> incrementExpression = (i => ++i);
编译器说,"An expression tree may not contain an assignment operator."为什么会这样?
4) 如果我能做到:
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
那为什么我做不到this?
public Expression<Func<T>> ToExpression<T>(Func<T> func)
{
return func;
}
这是我脑海中的一些想法碎片,它们有助于解开一些谜团。但我还在等待一个完整的答案。
首先,i => i + 1
不是 Func<int, int>
或 Func
任何东西。后者是 IL; Func 是 IL; TDelegate
是 IL。无法从 IL 返回表达式。
前者其实是一个表达式。它是 lamda 表达式.
的一些文本表示现在,即使是这样,从这种类型的文本类型的东西 i => i + 1
到 Expression<TDelegate>
?
但我猜没有,因为没有语法标记来表示文本 i => i + 1
。在编译器 DOM 中必须有一些 class 表示此内容,但在 LINQ 表达式 API 中没有任何内容用于此类事情。所以编译器使用它自己的 AST 来知道,"Oh, I just met with this sort of a piece of text. Let me parse it and turn it into an Expression
."
但这就是我的全部,如果是真的,那只能回答我问题的一部分。还在等待剩下的谜题被解开。
您几乎已经找到答案了。
i => i + 1
不是 Func<int, int>
。它是一个 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
和 returns 一个 int
,但除此之外,它是一个黑盒子。你输入一个数字,然后你得到一个数字,但你不再知道如何。
e
存储了将 1
添加到名为 i
的参数的事实,甚至 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
是您创建的自定义委托类型。
最后是"An expression tree may not contain an assignment operator",这主要是因为对于表达式树的预期用例,表达式包含赋值通常没有意义。不过,考虑到 .NET 表达式树能够表示赋值操作,这是一个有点武断的限制。