【发布时间】:2011-02-09 12:38:17
【问题描述】:
举个例子,为什么大多数 LINQ 运算符都接受Expression<Func<TSource>> 及其等效的Func<TSource>?
使用通用 Expression 类而不是直接使用 lambda 语法有什么好处/原因?
【问题讨论】:
举个例子,为什么大多数 LINQ 运算符都接受Expression<Func<TSource>> 及其等效的Func<TSource>?
使用通用 Expression 类而不是直接使用 lambda 语法有什么好处/原因?
【问题讨论】:
使用Expression<T> 可以显式创建expression tree - 这意味着您可以像处理数据一样处理构成查询的代码。
原因是 LINQ 提供程序(例如 LINQ to SQL)检查查询本身以确定将 C# 表达式转换为 T-SQL 查询的最佳方式。由于表达式树允许您将代码视为数据,因此提供者能够做到这一点。
【讨论】:
总的来说,两者的主要区别如下:
Expression<Func<...>> 是一个表达式树,它代表了原始源代码(它存储在一个树状数据结构中,非常接近原始 C# 代码)。在这种形式中,您可以分析源代码,并且 LINQ to SQL 等工具可以将表达式树(源代码)翻译成其他语言(例如,在 LINQ to SQL 的情况下为 SQL,但您也可以针对例如 JavaScript)。
Func<...> 是您可以执行的普通委托。在这种情况下,编译器将函数体编译为中间语言(IL),就像编译标准方法时一样。
值得一提的是,Expression<..> 有一个Compile 方法在运行时编译表达式并生成Func<...>,所以从第一个转换到第二个(有一些性能成本)。但是,从第二个到第一个没有转换,因为一旦你得到了IL,就很难(不可能)重构原始源代码。
【讨论】:
Func<T> 创建一个可执行函数。
Expression<Func<T>> 创建一个表达式树,允许您将函数中的代码用作数据。
表达式树允许您通过从 .NET 代码生成底层调用来执行 LINQ to SQL 和 LINQ to XML 之类的操作。
【讨论】:
Expression<Func<>> 表示尚未转换为代码的函数。 Func<> 是一个实际的可执行函数。使用前者允许您在调用它时将表达式转换为适当的函数。例如,对于 LINQ to SQL,这会将其转换为等效代码以执行 SQL 语句并返回指定的内容。使用 LINQ to 对象,它将使用 CLR 在客户端上执行代码。 Func<> 总是在 CLR 中执行——它是可执行代码。
【讨论】: