1

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

 delegate bool Foo(int x);

 Foo bar = x => x == 1;

将此委托传递给Enumerable扩展方法非常有意义,因为典型的预期参数是 a 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;
4

3 回答 3

3

这在规范中有所描述:

4.6 表达式树类型

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

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

于 2013-09-20T17:43:00.207 回答
2

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

但是对于 an 的赋值, 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(基本上从其他语言映射/减少)共享与 LINQ-To-Providers 相同的友好语法。因此,您可以编写一个具有相同含义但可以更改过滤和转换发生位置的语句。 GetEmployees().Where(e=>e.LastName=="Smith") 可以阅读相同的内容,但理论上可以描述在此框或数据库上进行过滤,或解析 xml 文件或任何数量的各种事物。

于 2013-09-20T17:42:19.803 回答
0

我相信这与如何在 IQueryable 上构建查询有关。该方法需要一个表达式树,因为它可以在内部查看和构建以匹配更优化(可能)的查询或更接近底层数据源的映射。因此,简单地传入 aFunc将只允许执行,而Expression < Func > 允许可以观察和执行的表达式树。

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

于 2013-09-20T17:40:19.707 回答