可枚举和可查询扩展方法的 Lambda 表达式参数

本文关键字:Lambda 表达式 参数 扩展 枚举 查询 方法 | 更新日期: 2023-09-27 18:32:07

lambda 表达式是一个匿名方法,它在幕后是一个委托,所以我可以做这样的事情:

 delegate bool Foo(int x);
 Foo bar = x => x == 1;

将此委托传递给Enumerable扩展方法是完全有意义的,因为典型的预期参数是Func,这是委托的简写:

 public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

但是,我不清楚如何将委托传递给如下所示的Queryable扩展方法:

 public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);

此方法需要一个Expression<TDelegate>参数,但传入 lambda 表达式是完全合法的。强制 lambda 表达式进入Expression<TDelegate>以便可以消耗它的机制是什么?

我熟悉可查询方法构建表达式树以供提供程序解析的事实,我只是对这个对我来说并不明显的方面感到好奇。

更新

我对自己的无知越来越

不无知了。Lambda 表达式不是委托,但可用于创建委托或表达式:

 Expression<Func<int, bool>> foo = c => c == 1;

编译器是否根据上下文推断类型?我猜一定是这样,因为这是不合法的:

var foo = c => c == 1;

可枚举和可查询扩展方法的 Lambda 表达式参数

这在规范中描述:

4.6 表达式树类型

如果存在从 lambda 表达式到委托类型 D 的转换, 表达式树类型 Expression<D> 也存在转换。 而将 lambda 表达式转换为委托类型 生成引用 lambda 的可执行代码的委托 表达式,转换为表达式树类型将创建一个 lambda 表达式的表达式树表示形式。 表达 树是 lambda 的有效内存中数据表示形式 表达式并使 lambda 表达式的结构透明 和显式

因此,存在从 lambda 到兼容表达式树类型的转换,编译器发出等效的表达式树,而不是创建委托。

很简单,你不能。但是,为了使IQueryable方法有用,VS2008及更高版本包含一个聪明的编译器技巧。单个语句的lambda expression可以同时分配给delegateExpression<TDelegate>。编译器通常会提升表达式并创建一个方法。

但是对于Expression<TDelegate>赋值,它将语句分解为句法含义,并将其转换为表达式树。

例如

Func<int,int> func = x=>x*x;
Expression<Func<int,int>> expression = x=>x*x;

第一个可能会变成一个带有乱码名称的静态方法,如下所示:

private static int <B012>SomeMethod(int x){
   return x*x;
}

其中,作为第二条语句将转换为以下内容:

ParameterExpression paramX = Expression.Parameter(typeof(int));
Expression<Func<int,int>> expression = Expression.Lambda<Func<int,int>>(
     Expression.Multiply(paramX,paramX),paramX);

但你不能做:

expression = func;

这是无效的,因为func是一个delegate。不过你可以这样做:

func=expression.Compile()

它将表达式编译为函数。

**请注意,建议的转换可能不是 100% 正确的。

他们这样做的原因是允许 LINQ-to-Objects(基本上是其他语言的 Map/Reduce)与 LINQ-To-Provider 共享相同的友好语法。因此,您可以编写一个语句,该语句的含义相同,但可以更改筛选和转换发生的位置。 GetEmployees().Where(e=>e.LastName=="Smith")可以读取相同的内容,但理论上可以描述对此框或数据库进行过滤,或解析 xml 文件或任何数量的各种内容。

我相信

这与查询如何建立在IQueryable上有关。该方法需要一个表达式树,因为它可以查看内部并对其进行结构化,以匹配更优化(可能)的查询或更贴近基础数据源的映射。因此,简单地传入Func只允许执行,而 Expression 允许可以观察和执行的表达式树。

另外,可能更仔细地回答您的确切问题,请查看此SO帖子。