其实有四个相关的问题:
1) 为什么可以这样做?
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
但是无法做到这一点?
LambdaExpression decrementorExpression = (i => i - 1);
在第二种情况下,编译器报告如下:“无法将 lambda 表达式转换为类型‘System.Linq.Expressions.LambdaExpression’,因为它不是委托(delegate)类型”
2) TDelegate
之间的转换在哪里和 Expression<TDelegate>
宣布?我想我记得以前见过它,但现在似乎找不到了。但我不能确定我是否看到了它。
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;
}
最佳答案
您几乎已经找到答案了。
i => i + 1
不是 Func<int, int>
.它是一个 lambda 表达式。 Lambda 表达式可以转换为匹配的委托(delegate)类型或匹配的表达式树类型。
如果将 lambda 表达式转换为委托(delegate)类型,编译器会将其编译为具有指定效果的 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
检索到任何信息关于它执行的操作。从其委托(delegate)类型可知,它需要一个 int
。并返回 int
,但除此之外,它是一个黑盒子。您输入一个数字,然后输出一个数字,但您不再知道如何操作。
e
,另一方面,存储 1
的事实添加到名为 i
的参数中,甚至那个 1
出现在 +
的 RHS 上.
存储在 e
中的额外信息对于那些解释表达式树的库来说通常是必不可少的,因此来自 Func<int, int>
的隐式转换至 Expression<Func<int, int>>
只是行不通:不再提供所需的信息。
至于LambdaExpression decrementorExpression = (i => i - 1);
,这是无效的,因为编译器无法确定您是否需要 Expression<Func<int, int>>
。 , 一个 Expression<Func<int, object>>
,或 Expression<MyFunc>
其中 MyFunc
是您创建的自定义委托(delegate)类型。
最后是“表达式树不能包含赋值运算符”,这主要是因为对于表达式树的预期用例,表达式包含赋值通常没有意义。不过,考虑到 .NET 表达式树能够表示赋值操作,这是一个有点武断的限制。
关于c# - 从 TDelegate 到 Expression<TDelegate> 的隐式转换在哪里声明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27738944/