Linq 简明教程
LINQ - Lambda Expressions
术语“Lambda 表达式”是从“lambda”演算派生而来的,而“lambda”演算本身是一种用于定义函数的数学表示法。作为 LINQ 等式的可执行部分的 lambda 表达式以一种方式转换逻辑,以便在运行时可以方便地传递给数据源。但是,lambda 表达式不仅限于在 LINQ 中寻找应用程序。
这些表达式用以下语法表示 -
(Input parameters) ⇒ Expression or statement block
以下是 lambda 表达式的示例 -
y ⇒ y * y
上述表达式指定了一个名为 y 的参数,并且 y 的值为平方。但是,无法以这种形式执行 lambda 表达式。下面展示了 C# 中 lambda 表达式的示例。
C
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace lambdaexample {
class Program {
delegate int del(int i);
static void Main(string[] args) {
del myDelegate = y ⇒ y * y;
int j = myDelegate(5);
Console.WriteLine(j);
Console.ReadLine();
}
}
}
VB
Module Module1
Private Delegate Function del(ByVal i As Integer) As Integer
Sub Main(ByVal args As String())
Dim myDelegate As del = Function(y) y * y
Dim j As Integer = myDelegate(5)
Console.WriteLine(j)
Console.ReadLine()
End Sub
End Module
当以上 C# 或 VB 代码被编译并执行时,它会生成以下结果 -
25
Async Lambdas
通过使用 async 关键字结合异步处理创建的 lambda 表达式称为异步 lambda。以下是一个异步 lambda 示例。
Func<Task<string>> getWordAsync = async()⇒ “hello”;
Lambda in Standard Query Operators
查询运算符中的 lambda 表达式由同个运算符根据需要进行求值,并持续处理输入序列中的每个元素,而不是整个序列。Lambda 表达式允许开发人员将自己的逻辑提供给标准查询运算符。在以下示例中,开发人员使用“Where”运算符通过使用 lambda 表达式从给定列表中回收奇数。
C
//Get the average of the odd Fibonacci numbers in the series...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace lambdaexample {
class Program {
static void Main(string[] args) {
int[] fibNum = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
double averageValue = fibNum.Where(num ⇒ num % 2 == 1).Average();
Console.WriteLine(averageValue);
Console.ReadLine();
}
}
}
Type Inference in Lambda
在 C# 中,类型推断在各种情况下得到了方便的使用,甚至无需显式指定类型。然而,在 lambda 表达式的情况下,类型推断仅在编译器必须满足时才起作用,前提是每个类型都已指定。我们来看一下下面的示例。
delegate int Transformer (int i);
这里,编译器利用类型推断根据 Transformer 的参数类型来利用 x 是一个整数这一事实。
Variable Scope in Lambda Expression
在 lambda 表达式中使用变量范围时有一些规则,例如在 lambda 表达式中启动的变量不得在外部方法中可见。还有一条规则,即捕获变量不得被垃圾回收,除非引用它的委托符合垃圾回收行为。此外,还有一条规则禁止 lambda 表达式中的 return 语句导致包围方法返回。
这里有一个示例来说明 lambda 表达式中的变量范围。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace lambdaexample {
class Program {
delegate bool D();
delegate bool D2(int i);
class Test {
D del;
D2 del2;
public void TestMethod(int input) {
int j = 0;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () ⇒ { j = 10; return j > input; };
// del2 will be invoked after TestMethod goes out of scope.
del2 = (x) ⇒ { return x == j; };
// Demonstrate value of j:
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j); // Invoke the delegate.
bool boolResult = del();
Console.WriteLine("j = {0}. b = {1}", j, boolResult);
}
static void Main() {
Test test = new Test();
test.TestMethod(5);
// Prove that del2 still has a copy of
// local variable j from TestMethod.
bool result = test.del2(10);
Console.WriteLine(result);
Console.ReadKey();
}
}
}
}
编译并执行上述代码后,将产生以下结果 −
j = 0
j = 10. b = True
True
Expression Tree
Lambda 表达式广泛用于 Expression Tree 构造。表达式树将代码赠送给类似树的数据结构,其中每个节点本身就是表达式,比如方法调用或二进制运算,比如 x<y。以下是一个用于构造表达式树的 lambda 表达式使用示例。
Statement Lambda
还有包含两个或三个语句的 statement lambdas ,但未用于构造表达式树。必须在语句 lambda 中编写 return 语句。
语句 lambda 的语法
(params)⇒ {statements}
Example of a statement lambda
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace lambdaexample {
class Program {
static void Main(string[] args) {
int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };
foreach (int i in source.Where(x ⇒
{
if (x <= 3)
return true;
else if (x >= 7)
return true;
return false;
}
))
Console.WriteLine(i);
Console.ReadLine();
}
}
}
编译并执行上述代码后,将产生以下结果 −
3
8
1
7
9
2
8
Lambda 作为基于方法的 LINQ 查询中的参数,永远不允许像 is 或 as 一样放在运算符的左侧,就像匿名方法一样。虽然 Lambda 表达式很像匿名方法,但它们完全不受限于仅用作委托。