記錄 Lambda,
兩種顯示形式:
// 第一種:運算式Lambda,右邊主體為運算式, (parameters) => expression // 第二種:陳述句Lambda,右邊主體為陳述句塊, (parameters) => { < sequence - of - statements > }
“=>”Lambda宣告運算子,左邊是lambda引數,右邊是lambda主體,這三個元素構成了Lambda運算式,
所有Lambda運算式都能轉換成委托,如果Lambda運算式沒有回傳值,則可以轉成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運算式有回傳值,則可以轉成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(); };
使用運算式作為主體的“運算式Lambda”可以轉換為運算式樹,陳述句Lambda則不可以轉換為運算式樹,
System.Linq.Expressions.Expression<Func<int, int>> e = x => x * x; System.Linq.Expressions.Expression<Action> e1 = () => Console.WriteLine("");
在需要用到委托型別或運算式的實體時,都可以使用 Lambda運算式,
// 泛型引數型別是Func<T,TResult>,根據運算式推理,則引數型別是Func<int,int>, var squaredNumbers = numbers.Select(x=>x*x);
// Action引數 Task.Run(() => { });
引數個數為0,必須有括號,
Func<int> func = () => 9;
引數個數為1,有無括號都可,
Func<int, string> func1 = x => x.ToString(); Func<int, string> func2 = (x) => x.ToString();
引數個數超1,必須有括號,
Action<string, string, int> action2 = (x, y, z) => Console.Write(x);
陳述句Lambda的主體可以包含任意數量的陳述句,通常不超過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運算式,async放在引數前,
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運算式(元組欄位可以取別名)
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;
編譯器可以推導輸入引數型別,但可以顯示指定型別,
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; int oddNumbers = numbers.Count((int n)=>n%2==1);
Lambda型別推理
lambda引數個數與委托型別輸入引數個數要一致;Lambda 的回傳值(如果有)必須能夠隱式轉換為委托的回傳型別;
Lambda 中的每個輸入引數必須都能夠隱式轉換為其對應的委托引數(舉例不成功,氣死我了)
// 兩個輸入引數,Lambda包含的引數個數推理出兩個,且型別為int Func<int, int, int> func = (x, y) => x * y; // 推理出的引數個數不對,編譯報錯 Func<int, int, int> func1 = (x, y, z) => x * y; // 結果型別可以隱式轉換成long Func<int, int, long> func2 = (x, y) => x * y; // 結果型別不能從int隱式轉換為string,編譯報錯 Func<int, int, string> func3 = (x, y) => x * y;
Lambda外部變數和變數范圍
Lambda捕獲的外部變數是否被回收,取決于參考變數的委托是否被回收,(下面代碼的updateCapturedLocalVariable被回收,j變數就會被回收),
Lambda引入的變數,外部無法訪問,(下面的temp變數)
Lambda無法捕獲in、out、ref引數,(下面的input如果用ref修飾,則lambda編譯報錯)
Lambda里的goto、break、continue只能在本主體起作用,外面不能跳進來,里面不能跳出去,
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;
// 此變數temp,外面不能訪問
var temp = 9; }; isEqualToCapturedLocalVariable = p => p == j; } } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/61607.html
標籤:C#
下一篇:C#值型別與參考型別
