最近交接的案子裡遇到了沒遇過的語法來測試順便紀錄一下使用方法與特性。
Lambda介紹
C#的匿名函式Lambda 從C# 3.0 .Net Framework 3.5開始支援,其特色在於無須定義函式名稱以及使用Lambda運算子 => 將左側的輸入參數與右側的Lambda主體分隔開來。
輸入參數 => Lambda主體
Lambda定義
在C#裡Lambda分成兩種形式來使用:
以運算式作為主體的運算式Lambda:
(input-parameters) => expression
程式範例: x => x + 1
以陳述式區塊作為主的陳述式Lambda,
使用大括弧{}包裹著程式,不同於運算式可以包含多行程式(大多數只會有兩、三行):
(input-parameters) => { <sequence-of-statements> }
程式範例: x => { Console.WriteLine(x + 1); }
Lambda轉換成委派加以封存
Lambda雖然不需要定義名稱,但是如果要把它傳遞給其他人使用,就需要一個可以封存Lambda的物件。其中運算式與陳述式Lambda 運算式兩者都可以被轉換成Action或是Func委派型別,其轉化成哪種委派取決於Lambda是否具有回傳值。具有回傳值的Lambda可以轉換成Func委派型別,否則可以轉換成Action委派型別。
Func Delegate
public
delegate TResult Func<out TResult>();
public delegate TResult Func<in T,out TResult>(T arg);
public delegate TResult Func<in T1, in T2,out TResult>(T1 arg1, T2 arg2);
...
T 輸入參數類型
TResult 輸出類型
運算式Lambda:
No Input
Func<string> func = () => "Hello World";
One input
Func<int, int> func = x => x+1;
Two input
Func<string, string, bool> func = (x, y) => x.StartsWith(y);
明確指定輸入類型
Func<int, string, bool> isTooLong = (int x, string s) => s.Length > x;
陳述式Lamdba:
No input
Func<string> func = () => { return "Hello World"; };
One Input
Func<int, int> func = x => { return x + 1 };
Action Delegate
public
delegatevoid Action();
public
delegatevoid Action<in T>(T arg);
public
delegate void Action<in T1,in T2>(T1 arg1, T2 arg2);
...
T 輸入參數類型
運算式Lambda:
No input
Action act = () => Console.WriteLine("Hello World");
One Input
Action<int> act = x => Console.WriteLne(x+1);
#Expression也可以是傳回型別為void的函式
陳述式Lamdba:
No input
Action act = () => { Console.WriteLine("Hello World"); };
One Input
Action<int> act = x => { Console.WriteLne(x+1); };
Lambda運算式中的擷取外部變數
在定義Lambda的範圍內使用到外部變數會被擷取儲存加以使用,因此Lambda可以在運算時參考到外部變數,但是外部變數必須確實指派同時擁有權限才能用於Lambda。
int y = 5;
Func<int, int> func = x => x + y;
Console.WriteLine(func(2));
//Output=7
C# 9.0 新功能
可以使用底線(_)來捨棄未使用到的輸入參數,在使用Lambda實現已定義的事件時可能很有用
Func<int, int, int> constant = (_, _) => 42
(_, _, var3, _, var5) => var3 * var5
(int _, int _) => 0