它是第十一個希臘字母,一個擁有失意、無奈、孤獨、低調等含義的流行符號,也指示一款稱爲「半條命」的遊戲。html
不過,此次我所講的是 C# 中的 Lambda。數組
Lambda 表達式,是一種簡化的匿名函數,可用於建立委託或表達式目錄樹。其次,你也能夠將 Lambda 表達式做爲參數進行傳遞,或者將它做用於函數調用值調用後返回的一個函數來使用。咱們常常在 LINQ 中使用 Lambda 表達式。異步
建立 Lambda 表達式的簡單語法形式:輸入參數 => 表達式或語句塊。其中,=> 爲 Lambda 運算符,可讀做「goes to」 。async
delegate int MyDel(int x); static void Main(string[] args) { MyDel myDel = x => x++; var j = myDel(5); }
建立表達式樹:函數
Expression<MyDel> myDel = x => x++;
=>
運算符和 = 運算符 (賦值運算符),具備相同的優先級,而且都是右結合運算。post
咱們常常在 LINQ 查詢中使用 Lambda 表達式,如做爲 Where<TSource> 的參數。該方法有多個重載,這裏只列舉了其中一個。測試
1 // 2 // 摘要: 3 // 基於謂詞篩選值序列。 4 // 5 // 參數: 6 // source: 7 // 要篩選的 System.Collections.Generic.IEnumerable<T>。 8 // 9 // predicate: 10 // 用於測試每一個元素是否知足條件的函數。 11 // 12 // 類型參數: 13 // TSource: 14 // source 中的元素的類型。 15 // 16 // 返回結果: 17 // 一個 System.Collections.Generic.IEnumerable<T>,包含輸入序列中知足條件的元素。 18 // 19 // 異常: 20 // System.ArgumentNullException: 21 // source 或 predicate 爲 null。 22 public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
參數是委託類型 Func<TSource, bool> predicate),這裏使用 Lambda 表達式進行建立我想應該是最合適的。還有,假如參數類型爲抽象類的 System.Linq.Expressions.Expression<Func>,其中 Func 委託是重載具備十六個參數的,你也可使用 Lambda 表達式建立對應的表達式樹。this
【注意】在 is 或 as 運算符的左側不容許使用 Lambda 表達式。url
表達式在 => 運算符右側,稱「lambda 表達式」。lambda 表達式經常使用於 LINQ 和構建表達式樹,它也容許返回結果。spa
基本形式:( 輸入參數 ) => 表達式 。
如:
( ) => true;
x => x == 1; (x) => x == 1; (x, y) => x == y;
【備註】當 lambda 表達式有且只有一個輸入參數的時侯,括號(「()」)纔是可選的。 括號內存在多個輸入參數時使用「,」進行分割。
你也能夠選擇顯式指定類型,通常只有在編譯器難以或沒法準確推斷輸入類型的時候。
Func<int, int, bool> func = (int x, int y) => x == y;
這裏使用空括號(「()」)指定零個輸入參數,而且能夠在 Lambda 的主體包含一個或多個方法進行調用。
() => YourMethod()
基本形式:( 輸入參數 ) => { 表達式 } 。
lambda 語句的主體能夠由任意數量的普通語句組成,不過,咱們通常寫的語句很少(三個左右吧)。
delegate void MyDel(string s); // ... MyDel myDel = n => { var s = n + " Fanguzai!"; Console.WriteLine(s); }; myDel("Hi,");
經過 async 和 await 關鍵字,咱們能夠很簡單並快速的建立包含異步處理的 lambda 表達式和語句。博主發表了約 8 篇關於異步的文章,你能夠 點擊進入目錄 。
這裏,我使用簡單的異步調用方式,編寫執行按鈕觸發的點擊事件,即調用異步方法 DoAsync
。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void button1_Click(object sender, EventArgs e) { await DoAsync(); } async Task DoAsync() { await Task.Delay(250); } }
如今,簡化上面的的 Click 事件,並加上 async。
public partial class Form1 : Form { public Form1() { InitializeComponent(); button1.Click += async (sender, e) => { await DoAsync(); }; } async Task DoAsync() { await Task.Delay(250); } }
許多 LINQ 中的參數都是一種委託類型的參數,如 Func<T, TResult>,能夠定義輸入參數以及返回類型。博主也發表了多篇關於 LINQ 的文章,你也能夠 點擊進入目錄 。
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
Func<int, bool> 表示:int 爲輸入參數,bool 爲返回值。
Func<int, int, bool> 表示:2個 int 爲輸入參數,一個 bool 爲返回值。
示例:
Func<int, bool> myFunc = x => x == 250; var result = myFunc(1314);
C# 的編譯器能夠自動推斷輸入參數的類型,即使是多個輸入參數,固然,你也能夠選擇顯式指定。
var nums = new[] { 2, 5, 0 }; var query = nums.Count(x => x > 2); var query2 = nums.Count<int>(x => x < 2);
【備註】不要將 => 和 >= 搞錯了,前者是 Lambda 運算符,後者是算術比較運算符。
編譯器會根據 Lambda 主體、參數的委託類型以及 C# 語言規範和其它等一些因素,對咱們所寫的 Lambda 進行類型推斷。
在這裏,因爲源數據是一個 int 數組,即我要查的數據爲 IEnumerable<int> 類型,編譯器在這裏自動推斷元素爲 int 類型,意味着 Count 方法內的 x 你能夠經過 「.」 在 VS 中顯示對應 int 類型的屬性和方法。
咱們能夠在 Lambda 的主體中引用範圍以外的變量。如:
var nums = new[] { 2, 5, 0 }; //int[] 類型 var compareNum = 2.5; var query = nums.Count(x => x == compareNum);
Lambda 中包含輸入參數的數量,必須與委託類型包含的參數數量一致。
Lambda 中的每一個輸入參數,必須都可以經過隱式轉換爲其對應的委託參數類型。
Lambda 中的返回值(若是有),必須可以隱式轉換爲委託的返回類型。
《C# 知識回顧 - 委託 delegate》、《C# 知識回顧 - 委託 delegate (續)》
《C# 知識回顧 - 事件入門》、《C# 知識回顧 - Event 事件》
《string 與 String,大 S 與小 S 之間沒有什麼不可言說的祕密》
《C# 知識回顧 - 你真的懂異常(Exception)嗎?》
《瞭解過入口函數 Main() 嗎?帶你用批處理玩轉 Main 函數》
@likeheart :「半年命」 -> 「半條命」。詳見評論區 10L。
【博主】反骨仔
【參考】微軟官方文檔