|
記錄 Lambda。 兩種顯示形式: // 第一種:表達(dá)式Lambda,右邊主體為表達(dá)式。 (parameters) => expression // 第二種:語句Lambda,右邊主體為語句塊。 (parameters) => { < sequence - of - statements > } “=>”Lambda聲明運(yùn)算符,左邊是lambda參數(shù),右邊是lambda主體,這三個(gè)元素構(gòu)成了Lambda表達(dá)式。
所有Lambda表達(dá)式都能轉(zhuǎn)換成委托。如果Lambda表達(dá)式?jīng)]有返回值,則可以轉(zhuǎn)成Action委托類型之一。 // Action有16種重載 Action action = () => Console.Write(""); Action<int, int> action1 = (x, y) => Console.WriteLine(x*y); Action<string, string, int> action2 = (x, y, z) => Console.Write(x); Action<string, string, int,long> action3 = (x, y, z,m) => Console.Write(x); 如果Lambda表達(dá)式有返回值,則可以轉(zhuǎn)成Func委托類型之一。 // Func有17種重載 Func<int> func = () => 9; Func<int, string> func1 = x => x.ToString(); Func<int, string> func2 = (x) => x.ToString(); Func<int, int,string> func3 = (x,y) => (x+y).ToString(); Func<int, int,string> func4 = (x,y) => { return (x + y).ToString(); };
使用表達(dá)式作為主體的“表達(dá)式Lambda”可以轉(zhuǎn)換為表達(dá)式樹,語句Lambda則不可以轉(zhuǎn)換為表達(dá)式樹。 System.Linq.Expressions.Expression<Func<int, int>> e = x => x * x; System.Linq.Expressions.Expression<Action> e1 = () => Console.WriteLine("");
在需要用到委托類型或表達(dá)式的實(shí)例時(shí),都可以使用 Lambda表達(dá)式。 // 泛型參數(shù)類型是Func<T,TResult>,根據(jù)表達(dá)式推理,則參數(shù)類型是Func<int,int>。 var squaredNumbers = numbers.Select(x=>x*x); // Action參數(shù) Task.Run(() => { });
參數(shù)個(gè)數(shù)為0,必須有括號(hào)。 Func<int> func = () => 9; 參數(shù)個(gè)數(shù)為1,有無括號(hào)都可。 Func<int, string> func1 = x => x.ToString(); Func<int, string> func2 = (x) => x.ToString(); 參數(shù)個(gè)數(shù)超1,必須有括號(hào)。 Action<string, string, int> action2 = (x, y, z) => Console.Write(x);
語句Lambda的主體可以包含任意數(shù)量的語句,通常不超過3句 Action<string> greet = name => { string greeting = $"Hello {name}!"; Console.WriteLine(greeting); }; // 不太好看 Action<string> greet1 = name => { string greeting = $"Hello {name}!"; Console.WriteLine(greeting); Console.WriteLine(greeting); Console.WriteLine(greeting); };
異步的Lambda表達(dá)式,async放在參數(shù)前。 public Form1() { button1.Click += async (sender, e) => await ExampleMethodAsync(); Action<string> action = async name => { await ExampleMethodAsync(); }; Action<string> action1 = async (name) => { await ExampleMethodAsync(); }; } private async Task ExampleMethodAsync() { await Task.Delay(1000); } 元組類型參與的Lambda表達(dá)式(元組字段可以取別名) Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3); var numbers = (2, 3, 4); var doubledNumbers = doubleThem(numbers); Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}"); Func<(int n1, int n2, int n3), (int a, int b, int c)> func = ns => (8 * ns.n1, 8 * ns.n2, 8 * ns.n3); var numbers1 = (5, 6, 7); var result = func(numbers1); var a = result.a; var b = result.b; var c = result.c; 編譯器可以推導(dǎo)輸入?yún)?shù)類型,但可以顯示指定類型。 int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; int oddNumbers = numbers.Count((int n)=>n%2==1); Lambda類型推理 lambda參數(shù)個(gè)數(shù)與委托類型輸入?yún)?shù)個(gè)數(shù)要一致;Lambda 的返回值(如果有)必須能夠隱式轉(zhuǎn)換為委托的返回類型; Lambda 中的每個(gè)輸入?yún)?shù)必須都能夠隱式轉(zhuǎn)換為其對應(yīng)的委托參數(shù)(舉例不成功,氣死我了) // 兩個(gè)輸入?yún)?shù),Lambda包含的參數(shù)個(gè)數(shù)推理出兩個(gè),且類型為int Func<int, int, int> func = (x, y) => x * y; // 推理出的參數(shù)個(gè)數(shù)不對,編譯報(bào)錯(cuò) Func<int, int, int> func1 = (x, y, z) => x * y; // 結(jié)果類型可以隱式轉(zhuǎn)換成long Func<int, int, long> func2 = (x, y) => x * y; // 結(jié)果類型不能從int隱式轉(zhuǎn)換為string,編譯報(bào)錯(cuò) Func<int, int, string> func3 = (x, y) => x * y;
Lambda外部變量和變量范圍 Lambda捕獲的外部變量是否被回收,取決于引用變量的委托是否被回收。(下面代碼的updateCapturedLocalVariable被回收,j變量就會(huì)被回收)。 Lambda引入的變量,外部無法訪問。(下面的temp變量) Lambda無法捕獲in、out、ref參數(shù)。(下面的input如果用ref修飾,則lambda編譯報(bào)錯(cuò)) Lambda里的goto、break、continue只能在本主體起作用,外面不能跳進(jìn)來,里面不能跳出去。 using System; namespace ConsoleApp4 { class Program { public static void Main() { var game = new VariableCaptureGame(); game.Run(90); // j=99 game.updateCapturedLocalVariable(9); // True,依舊可以訪問j變量 Console.WriteLine(game.isEqualToCapturedLocalVariable(99)); // False,依舊可以訪問j變量 Console.WriteLine(game.isEqualToCapturedLocalVariable(87)); } } public class VariableCaptureGame { internal Action<int> updateCapturedLocalVariable; internal Func<int, bool> isEqualToCapturedLocalVariable; public void Run(int input) { int j = 0; updateCapturedLocalVariable = x => { j = x + input;
|
|
|