Enumerable和Queryable扩展方法的Lambda表达式参数

时间:2013-09-20 17:25:17

标签: c# linq

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>以便它可以被消耗的机制是什么?

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

更新

我对自己的无知变得不那么无知了。 Lambda表达式不是委托,但可用于创建委托或表达式:

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

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

var foo = c => c == 1;

3 个答案:

答案 0 :(得分:3)

这在说明书中描述:

4.6表达式树类型

  

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

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

答案 1 :(得分:2)

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

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

e.g。

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;

这是无效的,因为funcdelegate。你可以这样做::

func=expression.Compile()

将表达式编译成func。

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

他们这样做的原因是允许LINQ到对象(基本上映射/从其他语言减少)与LINQ-To-Providers共享相同的友好语法。因此,您可以编写一个声明相同但可以更改过滤和转换发生位置的语句。 GetEmployees().Where(e=>e.LastName=="Smith") 可以阅读相同的内容,但理论上可以描述在此框或数据库上进行过滤,或者解析xml文件或任何数量的各种内容。

答案 2 :(得分:0)

我认为这与如何在IQueryable上构建查询有关。该方法需要表达式树,因为它可以是looked inside并且结构化以匹配更优化(可能)的查询或更接近底层数据源的映射。因此,简单地传入Func只允许执行,而Expression&lt; Func&gt;允许表达树,可以观察和执行。

此外,可能更贴切地回答您的确切问题{​​{3}}。