“Lambda 運算式”是一個匿名函數,它可以包含運算式和語句,並且可用於建立委託或運算式分類樹類型。
所有 Lambda 運算式都使用 Lambda 運算子,該運算子讀為“goes to”。該 Lambda 運算子的左邊是輸入參數(如果有),右邊包含運算式或語句塊。Lambda 運算式 x => x
* x 讀作“x goes to x times x”。可以將此運算式分配給委託類型,如下所示:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
建立運算式分類樹類型:
using System.Linq.Expressions;
// ...
Expression<del> = x => x * x;
=> 運算子具有與賦值運算子 (=) 相同的優先順序,並且是右結合運算子。
Lambda 用在基於方法的 LINQ 查詢中,作為諸如 和 等標準查詢運算子方法的參數。
使用基於方法的文法在 類中調用 方法時(像在 LINQ to Objects 和 LINQ to XML 中那樣),參數是委託類型 。使用 Lambda 運算式建立委託最為方便。例如,當您在 類中調用相同的方法時(像在 LINQ to SQL 中那樣),則參數類型是 <Func>,其中 Func 是包含至多五個輸入參數的任何 Func 委託。同樣,Lambda 運算式只是一種用於構造運算式分類樹的非常簡練的方式。儘管事實上通過 Lambda 建立的對象的類型是不同的,但 Lambda 使得 Where 調用看起來類似。
在前面的樣本中,請注意委託簽名具有一個 int 類型的隱式類型輸入參數,並返回 int。可以將 Lambda 運算式轉換為該類型的委託,因為該運算式也具有一個輸入參數 (x),以及一個編譯器可隱式轉換為 int 類型的傳回值。(以下幾節中將對型別推斷進行詳細討論。)使用輸入參數 5 調用委託時,它將返回結果 25。
在 或 運算子的左側不允許使用 Lambda。
適用於匿名方法的所有限制也適用於 Lambda 運算式。
Lambda 運算式
運算式在右邊的 Lambda 運算式稱為“Lambda 運算式”。Lambda 運算式在構造時廣泛使用。Lambda 運算式返回運算式的結果,並採用以下基本形式:
(input parameters) => expression
只有在 Lambda 有一個輸入參數時,括弧才是可選的;否則括弧是必需的。兩個或更多輸入參數由括在括弧中的逗號分隔:
(x, y) => x == y
有時,編譯器難於或無法推斷輸入類型。如果出現這種情況,您可以按以下樣本中所示方式顯式指定類型:
(int x, string s) => s.Length > x
使用空括弧指定零個輸入參數:
() => SomeMethod()
Lambda 語句與 Lambda 運算式類似,只是語句括在大括弧中:
(input parameters) => {statement;}
Lambda 語句的主體可以包含任意數量的語句;但是,實際上通常不會多於兩個或三個語句。
delegate void TestDelegate(string s);…TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };myDel("Hello");
Lambda 可以引用“外部變數”,這些變數位於在其中定義 Lambda 的封閉方法或類型的範圍內。將會儲存通過這種方法捕獲的變數以供在 Lambda 運算式中使用,即使變數將以其他方式超出範圍或被作為記憶體回收。必須明確地分配外部變數,然後才能在 Lambda 運算式中使用該變數。下面的樣本示範這些規則:
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:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j);
// Invoke the delegate.
bool boolResult = del();
// Output: j = 10 b = True
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);
// Output: True
Console.WriteLine(result);
Console.ReadKey();
}
}