LINQ - Lambda表达式

术语"Lambda表达式"的名称来源于"lambda"演算,后者又是用于定义函数的数学符号. Lambda表达式作为LINQ方程的可执行部分在运行时以某种方式转换逻辑,因此它可以方便地传递给数据源.但是,lambda表达式不仅限于在LINQ中查找应用程序.

这些表达式由以下语法表示 :

 
(输入参数)⇒表达式或语句块

以下是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

Expression Lambda

由于上面显示的lambda表达式语法中的表达式位于右侧,因此这些表达式也称为表达式lambda.

Async Lambdas

通过使用async关键字合并异步处理而创建的lambda表达式称为async lambdas.下面是异步lambda的示例.

Func<Task<string>> getWordAsync = async()&rArr; "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 &rArr; 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 = () &rArr; { j = 10; return j > input; };

            // del2 will be invoked after TestMethod goes out of scope.
            del2 = (x) &rArr; { 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

还有语句lambdas 由两个或三个语句组成,但不用于构造表达式树. return语句必须写在语句lambda中.

语句语法lambda

(params)&rArr; {statements}

使用System语句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 &rArr; 
            {
               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查询中被用作基于方法的参数,并且从不允许在运算符的左侧有一个位置,如 as 就像匿名方法一样.虽然Lambda表达式是非常相似的匿名方法,但它们并不仅限于仅用作代理.

使用lambda表达式时要记住的要点

  • lambda表达式可以返回一个值并且可以包含参数.

  • 参数可以是用lambda表达式以无数种方式定义.

  • 如果lambda表达式中有单个语句,则不需要大括号,如果有多个语句,大括号以及返回值是必不可少的.

  • 使用lambda表达式,可以访问lambda表达式块之外的变量通过一个称为闭包的功能.应谨慎使用闭包以避免任何问题.

  • 在任何lambda表达式中都不可能执行任何不安全的代码.

  • Lambda表达式不适用于运算符的左侧.