介紹
Lambda 表達式是一種可用於創建 委托 或 表達式目錄樹 類型的 匿名函數 ,但是比匿名函數更簡潔。
通過使用 lambda 表達式,可以寫入可作為參數傳遞或作為函數調用值返回的本地函數。 Lambda 表達式對於編寫 LINQ 查詢表達式特別有用。
Lambda表達式本身可划分為兩種類型:語句Lambda和表達式Lambda。
若要創建 Lambda 表達式,需要在 Lambda 運算符 => (goes to)左側指定輸入參數(如果有),然后在另一側輸入表達式或語句塊。
格式
(input parameters) => expression
或者
(input parameters) => {statement;}
左邊參數列表可以有多個參數,一個參數,或者無參數;參數類型可以隱式或者顯式,參數類型可以忽略,因為可以根據使用的上下文進行推斷而得到。
僅當 lambda 只有一個輸入參數時,括號才是可選的;否則括號是必需的。
例如:
(x, y) => x * y //多參數,隱式類型=> 表達式
x => x * 10 //單參數,隱式類型=>表達式
x => { return x * 10; } //單參數,隱式類型=>語句塊
(int x) => x * 10 //單參數,顯式類型=>表達式
(int x) => { return x * 10; } //單參數,顯式類型=>語句塊
() => Console.WriteLine() //無參數
例如,lambda 表達式 x => x * x
指定名為 x
的參數並返回 x
的平方值。
Lambda表達式與委托類型
如下面的示例所示,你可以將此表達式分配給委托類型:
delegate int del(int i); static void Main(string[] args) { del myDelegate = x => x * x; int j = myDelegate(5); //j = 25 }
=>
運算符具有與賦值運算符 (=
) 相同的優先級並且是右結合運算
使用 Lambda 表達式創建該委托最為方便。
Lambda表達式可以被轉成委托類型,但必須滿足以下幾點:
1.兩者參數個數相同
2.參數類型相同,注意隱式類型要參與類型辨析
3.委托的返回類型要與Lambda的相同,不論是表達式還是語句塊
Lambda與匿名函數的對比:

public delegate int DelegateTest(int n1, int n2); static void Main(string[] args) { //委托:方法作為參數傳遞 var r1 = Result(3, 4, Sum); //使用匿名方法傳遞委托 var r4 = Result(3,4,delegate(int x,int y){return x+y;}); //語句lambda傳遞委托 var r2 = Result(3, 4, (a, b) => { return a - b; }); //lambda傳遞委托 var r3 = Result(3, 4, (a, b) => a * b); Console.ReadLine(); } public static int Result(int a, int b, DelegateTest @delegate) { return @delegate(a, b); } public static int Sum(int a, int b) { return a + b; }
Func和Lambda
更加簡化了代碼量,此時就不用像上面一樣就行聲明委托直接可以用
public static void LambdaFunc() { Func<string, string, string> getFunc = (p1, p2) => { return p1 + " " + p2; }; Console.WriteLine(getFunc("我是第一個參數","我是第二個參數")); }
Linq和Lambda
//獲取所有的用戶ID
List<string> gidList = Users.Select(p => p.Gid).ToList();
//獲取所有大於6的集合
aaList = retList.Where(p => p > 6).ToList();
異步 lambda
通過使用 async 和 await 關鍵字,你可以輕松創建包含異步處理的 lambda 表達式和語句。 例如,下面的 Windows 窗體示例包含一個調用和等待異步方法 ExampleMethodAsync
的事件處理程序。

public partial class Form1 : Form { public Form1() { InitializeComponent(); button1.Click += async (sender, e) => { await ExampleMethodAsync(); textBox1.Text += "\r\nControl returned to Click event handler.\n"; }; } private async Task ExampleMethodAsync() { // The following line simulates a task-returning asynchronous process. await Task.Delay(1000); } }
Lambda表達式的內部機制
Lambda表達式並非CLR內部的固有構造,它們的實現是由C#編譯器在編譯時生成的。Lambda表達式為“以內嵌方式聲明委托”模式提供一個對應的C#與語言構造。所以,當我們編寫lambda時,編譯器實際上會生成一系列代碼,就以上面的代碼為例,通過反編譯工具查看生成的等價代碼:
Main方法中使用lambda表達式傳遞委托,編譯后生成的是匿名函數。這也證明了上面說的lambda其實就是簡化了的匿名函數。
再來看看上面的匿名方法 delegate(int x,int y){return x+y;}和lambad表達式(a, b) => { return a - b; }、(a, b) => a * b),編譯后實際生成了3個靜態方法 <Main>b_0,<Main>b_1和<Main>b_2,也就是說,在調用的時候還是由這3個靜態方法去分別實例化成委托,並作為參數傳遞的,又回到了最初對委托的了解:委托實現把方法作為參數傳入到另一個方法。
表達式樹
表達式樹是一種允許將lambda表達式表示為樹狀數據結構而不是可執行邏輯的代碼。
表達式樹的創建:
1.通過Lambda表達式創建表達式樹
下面的代碼演示將lambda表達式表示為可執行代碼和表達式樹:
Func<int, int> res = x => x + 1; //Code
Expression<Func<int, int>> exp = x => x + 1; //Data
進行上面的賦值之后,委托res引用返回x+1的方法,表達式樹exp引用描述表達式x=>x+1的數據結構,這是兩者的明顯區別。
2.通過API創建表達式樹
要使用API創建表達式樹,需要使用Expression類。該類提供創建特定類型的表達式樹節點的靜態方法,例如:ParameterExpression(表示一個變量或參數)或MethodCallExpression(表示一個方法調用)。下面演示使用API創建一個表達式樹:

static void Main(string[] args) {//創建表達式樹:Expression<Func<int, int>> exp = x => x + 1; ParameterExpression param = Expression.Parameter(typeof(int),"x"); ConstantExpression value = Expression.Constant(1, typeof(int)); BinaryExpression body = Expression.Add(param, value); Expression<Func<int, int>> lambdatree = Expression.Lambda<Func<int, int>>(body, param); Console.WriteLine("參數param:{0}", param); Console.WriteLine("描述body:{0}", body); Console.WriteLine("表達式樹:{0}", lambdatree); //解析表達式樹: //取得表達式樹的參數 ParameterExpression dparam = lambdatree.Parameters[0] as ParameterExpression; //取得表達式樹描述 BinaryExpression dbody = lambdatree.Body as BinaryExpression; //取得節點 ParameterExpression left = dbody.Left as ParameterExpression; ConstantExpression right = body.Right as ConstantExpression; Console.WriteLine("解析出的表達式:{0}=>{1} {2} {3}", param.Name, left.Name, body.NodeType, right.Value); Console.ReadLine(); }
運行結果:
關於表達式樹:表達式樹這一概念的引入,使得程序可以將一個lambda表達式編譯成數據來表示,而不是編譯成一個表示為委托的具體實現(靜態方法)。利用這一特性,Linq to Sql和Linq to Xml等庫能解釋表達式樹,並在CIL之外的上下文中使用。
更多參考: