举个例子,为什么大多数LINQ运算符接受Expression<Func<TSource>>
及其等价的Func<TSource>
?
使用泛型Expression
类而不是直接lambda语法有什么好处/原因?
答案 0 :(得分:59)
使用Expression<T>
明确创建expression tree - 这意味着您可以将构成查询的代码视为数据。
原因是LINQ提供程序(例如LINQ to SQL)检查查询本身以确定将C#表达式转换为T-SQL查询的最佳方法。由于表达式树允许您将代码视为数据,因此提供程序可以执行此操作。
答案 1 :(得分:31)
总之,两者之间的主要区别如下:
Expression<Func<...>>
是表达式树,它代表原始源代码(它存储在非常接近的树状数据结构中到原来的C#代码)。在这种形式中,您可以分析源代码和LINQ to SQL之类的工具可以将表达式树(源代码)转换为其他语言(例如,在LINQ to SQL的情况下使用SQL,但您也可以使用例如JavaScript)。
Func<...>
是您可以执行的普通委托。在这种情况下,编译器将函数体编译为中间语言(IL),就像编译标准方法一样。
值得一提的是Expression<..>
有Compile
方法在运行时编译表达式并生成Func<...>
,因此从第一个转换为第二个(有一些性能成本)。但是,没有从第二个到第一个的转换,因为一旦获得IL,重建原始源代码是非常困难的(不可能的)。
答案 2 :(得分:18)
Func<T>
创建一个可执行函数。
Expression<Func<T>>
创建一个表达式树,允许您将函数中的代码用作数据。
表达式树允许您通过从.NET代码生成基础调用来执行LINQ to SQL和LINQ to XML等操作。
答案 3 :(得分:7)
Expression<Func<>>
是尚未转换为代码的函数的表示。 Func<>
是一个实际的可执行函数。使用前者允许您在调用表达式时将表达式转换为适当的函数。例如,使用LINQ to SQL,这会将其转换为执行SQL语句并返回指定内容的等效代码。使用LINQ to对象,它将使用CLR在客户端上执行代码。 Func<>
始终在CLR中执行 - 它是可执行代码。