LINQ - 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

表示式 Lambda

由於上述 Lambda 表示式語法中的表示式位於右側,因此它們也稱為表示式 Lambda。

非同步 Lambda

透過使用 async 關鍵字加入非同步處理建立的 Lambda 表示式稱為非同步 Lambda。下面是一個非同步 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,它包含兩到三個語句,但不用於構建表示式樹。語句 Lambda 必須編寫 return 語句。

語句 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 查詢中的引數,並且不允許像匿名方法一樣位於運算子(如isas)的左側。儘管 Lambda 表示式與匿名方法非常相似,但它們並不侷限於僅用作委託。

使用 Lambda 表示式時需要注意的幾點

  • Lambda 表示式可以返回值,並且可以具有引數。

  • 可以使用多種方法定義 Lambda 表示式的引數。

  • 如果 Lambda 表示式中只有一個語句,則不需要花括號;如果有多個語句,則必須編寫花括號和返回值。

  • 使用 Lambda 表示式,可以透過稱為閉包的功能訪問 Lambda 表示式塊外部的變數。應謹慎使用閉包以避免任何問題。

  • 不可能在任何 Lambda 表示式內執行任何不安全程式碼。

  • Lambda 表示式不能用於運算子的左側。

廣告
© . All rights reserved.