Linq 简明教程

LINQ - Lambda Expressions

术语“Lambda 表达式”是从“lambda”演算派生而来的,而“lambda”演算本身是一种用于定义函数的数学表示法。作为 LINQ 等式的可执行部分的 lambda 表达式以一种方式转换逻辑,以便在运行时可以方便地传递给数据源。但是,lambda 表达式不仅限于在 LINQ 中寻找应用程序。

The term ‘Lambda expression’ has derived its name from ‘lambda’ calculus which in turn is a mathematical notation applied for defining functions. Lambda expressions as a LINQ equation’s executable part translate logic in a way at run time so it can pass on to the data source conveniently. However, lambda expressions are not just limited to find application in LINQ only.

这些表达式用以下语法表示 -

These expressions are expressed by the following syntax −

(Input parameters) ⇒ Expression or statement block

以下是 lambda 表达式的示例 -

Here is an example of a lambda expression −

y ⇒ y * y

上述表达式指定了一个名为 y 的参数,并且 y 的值为平方。但是,无法以这种形式执行 lambda 表达式。下面展示了 C# 中 lambda 表达式的示例。

The above expression specifies a parameter named y and that value of y is squared. However, it is not possible to execute a lambda expression in this form. Example of a lambda expression in C# is shown below.

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 代码被编译并执行时,它会生成以下结果 -

When the above code of C# or VB is compiled and executed, it produces the following result −

25

Expression Lambda

由于 lambda 表达式语法中的表达式位于右侧,因此它们也被称为表达式 lambda。

As the expression in the syntax of lambda expression shown above is on the right hand side, these are also known as expression lambda.

Async Lambdas

通过使用 async 关键字结合异步处理创建的 lambda 表达式称为异步 lambda。以下是一个异步 lambda 示例。

The lambda expression created by incorporating asynchronous processing by the use of async keyword is known as async lambdas. Below is an example of async lambda.

Func<Task<string>> getWordAsync = async()⇒ “hello”;

Lambda in Standard Query Operators

查询运算符中的 lambda 表达式由同个运算符根据需要进行求值,并持续处理输入序列中的每个元素,而不是整个序列。Lambda 表达式允许开发人员将自己的逻辑提供给标准查询运算符。在以下示例中,开发人员使用“Where”运算符通过使用 lambda 表达式从给定列表中回收奇数。

A lambda expression within a query operator is evaluated by the same upon demand and continually works on each of the elements in the input sequence and not the whole sequence. Developers are allowed by Lambda expression to feed their own logic into the standard query operators. In the below example, the developer has used the ‘Where’ operator to reclaim the odd values from given list by making use of a lambda expression.

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

编译并执行上述代码后,将产生以下结果 −

When the above code is compiled and executed, it produces the following result −

7.33333333333333

Type Inference in Lambda

在 C# 中,类型推断在各种情况下得到了方便的使用,甚至无需显式指定类型。然而,在 lambda 表达式的情况下,类型推断仅在编译器必须满足时才起作用,前提是每个类型都已指定。我们来看一下下面的示例。

In C#, type inference is used conveniently in a variety of situations and that too without specifying the types explicitly. However in case of a lambda expression, type inference will work only when each type has been specified as the compiler must be satisfied. Let’s consider the following example.

delegate int Transformer (int i);

这里,编译器利用类型推断根据 Transformer 的参数类型来利用 x 是一个整数这一事实。

Here the compiler employ the type inference to draw upon the fact that x is an integer and this is done by examining the parameter type of the Transformer.

Variable Scope in Lambda Expression

在 lambda 表达式中使用变量范围时有一些规则,例如在 lambda 表达式中启动的变量不得在外部方法中可见。还有一条规则,即捕获变量不得被垃圾回收,除非引用它的委托符合垃圾回收行为。此外,还有一条规则禁止 lambda 表达式中的 return 语句导致包围方法返回。

There are some rules while using variable scope in a lambda expression like variables that are initiated within a lambda expression are not meant to be visible in an outer method. There is also a rule that a captured variable is not to be garbage collected unless the delegate referencing the same becomes eligible for the act of garbage collection. Moreover, there is a rule that prohibits a return statement within a lambda expression to cause return of an enclosing method.

这里有一个示例来说明 lambda 表达式中的变量范围。

Here is an example to demonstrate variable scope in lambda expression.

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();
         }
      }
   }
}

编译并执行上述代码后,将产生以下结果 −

When the above code is compiled and executed, it produces the following result −

j = 0
j = 10. b = True
True

Expression Tree

Lambda 表达式广泛用于 Expression Tree 构造。表达式树将代码赠送给类似树的数据结构,其中每个节点本身就是表达式,比如方法调用或二进制运算,比如 x<y。以下是一个用于构造表达式树的 lambda 表达式使用示例。

Lambda expressions are used in Expression Tree construction extensively. An expression tree give away code in a data structure resembling a tree in which every node is itself an expression like a method call or can be a binary operation like x<y. Below is an example of usage of lambda expression for constructing an expression tree.

Statement Lambda

还有包含两个或三个语句的 statement lambdas ,但未用于构造表达式树。必须在语句 lambda 中编写 return 语句。

There is also statement lambdas consisting of two or three statements, but are not used in construction of expression trees. A return statement must be written in a statement lambda.

语句 lambda 的语法

Syntax of statement 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();
      }
   }
}

编译并执行上述代码后,将产生以下结果 −

When the above code is compiled and executed, it produces the following result −

3
8
1
7
9
2
8

Lambda 作为基于方法的 LINQ 查询中的参数,永远不允许像 isas 一样放在运算符的左侧,就像匿名方法一样。虽然 Lambda 表达式很像匿名方法,但它们完全不受限于仅用作委托。

Lambdas are employed as arguments in LINQ queries based on methods and never allowed to have a place on the left side of operators like is or as just like anonymous methods. Although, Lambda expressions are much alike anonymous methods, these are not at all restricted to be used as delegates only.

Points to remember while using lambda expressions

  1. A lambda expression can return a value and may have parameters.

  2. Parameters can be defined in a myriad of ways with a lambda expression.

  3. If there is single statement in a lambda expression, there is no need of curly brackets whereas if there are multiple statements, curly brackets as well as return value are essential to write.

  4. With lambda expressions, it is possible to access variables present outside of the lambda expression block by a feature known as closure. Use of closure should be done cautiously to avoid any problem.

  5. It is impossible to execute any unsafe code inside any lambda expression.

  6. Lambda expressions are not meant to be used on the operator’s left side.