LINQ – Lambda 表达式
LINQ – Lambda 表达式
术语“Lambda 表达式”的名称源自“lambda”演算,而后者又是一种用于定义函数的数学符号。Lambda 表达式作为 LINQ 方程的可执行部分在运行时以某种方式转换逻辑,因此它可以方便地传递到数据源。但是,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
表达式 Lambda
由于上面显示的 lambda 表达式语法中的表达式位于右侧,因此它们也称为表达式 lambda。
异步 Lambda
通过使用 async 关键字合并异步处理而创建的 lambda 表达式称为 async lambdas。以下是异步 lambda 的示例。
Func<Task<string>> getWordAsync = async()⇒ “hello”;
标准查询运算符中的 Lambda
查询运算符中的 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(); } } }
VB
Module Module1 Sub Main() Dim fibNum As Integer() = {1, 1, 2, 3, 5, 8, 13, 21, 34} Dim averageValue As Double = fibNum.Where(Function(num) num Mod 2 = 1).Average() Console.WriteLine(averageValue) Console.ReadLine() End Sub End Module
当上面的代码被编译和执行时,它会产生以下结果 –
7.33333333333333
Lambda 中的类型推断
在 C# 中,类型推断可以在各种情况下方便地使用,而且无需明确指定类型。但是,在 lambda 表达式的情况下,类型推断仅在每个类型都已指定为编译器必须满足时才有效。让我们考虑以下示例。
delegate int Transformer (int i);
这里编译器使用类型推断来利用 x 是整数这一事实,这是通过检查 Transformer 的参数类型来完成的。
Lambda 表达式中的变量范围
在 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
表达式树
Lambda 表达式广泛用于表达式树的构建。表达式树在类似于树的数据结构中提供代码,其中每个节点本身都是一个表达式,如方法调用,也可以是二元运算,如 x<y。下面是使用 lambda 表达式构建表达式树的示例。
语句 Lambda
还有由两个或三个语句组成的语句 lambda,但不用于构建表达式树。return 语句必须写在语句 lambda 中。
语句 lambda 的语法
(params)⇒ {statements}
语句 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查询参数,决不允许有一个地方运营商的左侧就像是或作为就像匿名方法。尽管 Lambda 表达式与匿名方法非常相似,但它们完全不限于仅用作委托。
使用 lambda 表达式时要记住的要点
-
一个 lambda 表达式可以返回一个值并且可以有参数。
-
可以使用 lambda 表达式以多种方式定义参数。
-
如果 lambda 表达式中有单个语句,则不需要大括号,而如果有多个语句,则必须编写大括号和返回值。
-
使用 lambda 表达式,可以通过称为闭包的功能访问存在于 lambda 表达式块之外的变量。应谨慎使用封闭件以避免出现任何问题。
-
不可能在任何 lambda 表达式中执行任何不安全的代码。
-
Lambda 表达式不应用于运算符的左侧。