我不确定你到底要什么;但至少我可以尝试提供一些关于Expression
lambda 函数和 lambda 函数的区别的见解,它们都是主流 .NET 语言(C#、VB.NET)的语言特性。
基本上,lambda 函数是一个匿名(未命名)函数,可以在另一个函数的范围内声明。在 C#(语言版本 3)中,它会这样声明:
(
参数列表 函数体)
=>
例如:
void Foo()
{
// two equivalent lambda functions with one double parameter 'x' each:
var square = (double x) => x * x;
var square2 = (double x) => { return x * x; };
// lambda function that doesn't take any arguments:
var doSomething = () => { Console.WriteLine("Hello."); }
}
(请注意,egsquare
不是 lambda 函数的名称,而是引用它的变量的名称。lambda 函数本身没有该方法的任何名称void Foo()
!)
C# 版本 2 已经可以实现非常相似的东西,称为匿名委托:
delegate(double x) { return x * x; } // is equivalent to: (double x) => x * x
使用 LINQ(在命名空间中)将表达式System.Linq.Expressions
添加到 .NET 。基本上,它们是简单的数据结构,以抽象语法树(AST) 的形式描述任何可以用 C# 或 VB.NET 表示的计算。举个例子:
// case 1. IEnumerable<int>:
IEnumerable<int> xs = ...;
IEnumerable<int> queryXs = from x in xs where x > 0 select x;
// case 2. IQueryable<int>:
IQueryable<int> ys = ...;
IEnumerable<int> queryYs = from y in ys where y > 0 select y;
这两个查询是相同的,除了ys
是 typeIQueryable<int>
而不是IEnumerable<int>
. C#编译器会将上述两个查询翻译成不同的代码,即:
// case 1. IEnumerable<int>:
IQueryable<int> xs = ...;
IEnumerable<int> queryXs = xs.Where<int>(delegate (int x) { return x > 0; });
// case 2. IQueryable<int>:
IEnumerable<int> ys = ...;
ParameterExpression yParameter = Expression.Parameter(typeof(int), "y");
IEnumerable<int> queryYs.Where<int>(
Expression.Lambda<Func<int, bool>>(
Expression.GreaterThan(
yParameter,
Expression.Constant(0, typeof(int))),
new ParameterExpression[] { yParameter }));
如果您研究后者,您会看到对于 的查询IQueryable<int>
,编译器已将解析后的查询输出为描述查询的数据结构。另一方面,对于针对 的查询IEnumerable<int>
,它只输出执行查询的代码。事实证明,编译器具有特殊的魔力,仅使用类型生成它已解析为表达式树的内容。IQueryable<T>
表达式,IQueryable<T>
因此允许您在运行时分析查询并在实际运行之前对其执行优化和其他转换。这被 LINQ to SQL 大量使用,以编写智能、优化的 SQL 查询:
想象一下,数据库被要求提供某列x
> 0 的所有行。
如果您对/解析表达式树的内部结构感兴趣,请查看 Bart De Smet 的深入博客系列,从IQueryable 故事 - LINQ to LDAP - 第 0 部分:简介开始。