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