C# - ラムダ式とデリゲート型
処理をひとつの固まりとして扱うのがラムダ式。
(引数リスト) => {処理}; (引数リスト) => {処理; return 戻り値;};
引数がひとつの場合や、処理が単文の場合は括弧を省略できる。また処理が単文の場合はreturnも省略できる。
ラムダ式は、デリゲート型の変数や引数として扱うことができる。
デリゲート型には以下の様な種類がある。
Action型
値を返さない処理を扱う。
Action<引数の型リスト> 変数 = (引数リスト) => {処理};
Func型
値を返す処理を扱う
Func<引数の型リスト, 返り値の型> 変数 = (引数リスト) => {処理; return 戻り値;};
Predicate型
引数について処理を行った結果のbool値を返す
Predicate<引数の型> 変数 = (引数) => { 処理; return bool値; };
Comparison型
2つの引数の大小の判定を行う。int値を返す。
- 処理結果 < 0 : xがyより小さい
- 処理結果 == 0 : xとyは等しい
- 処理結果 > 0 : xがyより大きい
Comparison<引数の型> 変数 = (x, y) => { 処理; return int値; };
Converter型
引数で与えられたオブジェクトに対し処理を行い、出力型として値を返す。
使用例は明日の日記に記載。
Converter<引数の型,出力の型> 変数 = x => { 処理; return 出力の型の値; };
using System; using System.Collections.Generic; //ラムダ式 class MyMain { public static void Main(string[] args) { //値を返さないデリゲートにラムダ式を代入 // Action<引数の型リスト> 変数 = (引数リスト) => {処理}; Action<int, int> a = (x, y) => { Console.WriteLine("{0} + {1} = {2}",x, y, x + y); Console.WriteLine("{0} * {1} = {2}",x, y, x * y); }; a(2, 3); //2 + 3 = 5 //2 * 3 = 6 // 引数が1個の場合、処理が単文の場合は括弧を省略できる Action<int> b = x => Console.WriteLine("{0} * (-1) = {1}",x, x * -1); b(4); //4 * (-1) = -4 //値を返すデリゲートにラムダ式を代入 // Func<引数の型リスト, 返り値の型> 変数 = (引数リスト) => {処理; return 戻り値;}; Func<int, int, string> c = (x, y) => { var i = x + y; return i.ToString("D04"); }; Console.WriteLine(c(5, 6)); // 0011 // 処理が単文の場合、returnは省略できる Func<int, string> d = x => x.ToString("D05"); Console.WriteLine(d(5)); // 00005 //ラムダ式を引数にして関数を呼ぶ Console.WriteLine(MyFunc( (x,y) => x + y, 4, 5) );//9 Console.WriteLine(MyFunc( (x,y) => x - y, 4, 5) );//-1 Console.WriteLine(MyFold( (x,y) => x + y, new int[]{1,2,3,4,5} ) );//15 //引数が条件を満たすか否かのデリゲートにラムダ式を代入 // Predicate<引数の型> 変数 = (引数) => { 判別式 }; Predicate<int> p = x => x % 2 == 0; Console.WriteLine(p(2)); // True Console.WriteLine(p(3)); // False var selected = MySelect(p, new List<int>(){1,2,3,4,5}); foreach(var e in selected){ Console.Write("{0} ", e); } Console.WriteLine(); // 2 4 //2つの引数を比較するデリゲートにラムダ式を代入 // Comparison<引数の型> 変数 = (x, y) => { 判別式 }; // 戻り値r // r < 0 : xがyより小さい // r == 0 : xとyは等しい // r > 0 : xがyより大きい Comparison<int> cp = (x, y) => x - y; Console.WriteLine( MyCompare(cp, new int[]{1,2,5,4,3}) ); //5 Console.WriteLine( MyCompare((x,y)=>y-x, new int[]{1,2,5,4,3}) ); //1 } //ラムダ式を引数にする関数 private static int MyFunc(Func<int, int, int> f, int x, int y) { return f(x, y); } private static int MyFold(Func<int, int, int> f, int[] ary) { //null許容型 int? v = null; foreach(var e in ary) { if( v.HasValue ){ v = f((int)v, e); } else{ v = e; } } return (int)v; } private static List<int> MySelect(Predicate<int> p, List<int> ary) { var v = new List<int>(); foreach(var e in ary) { if( p(e) ){ v.Add( e ); } } return v; } private static int MyCompare(Comparison<int> cp, int[] ary) { //null許容型 int? v = null; foreach(var e in ary) { if( v.HasValue ){ v = cp((int)v, e) > 0 ? (int)v : e; } else{ v = e; } } return (int)v; } }
参考
- https://docs.microsoft.com/ja-jp/dotnet/api/system.action-1
- https://docs.microsoft.com/ja-jp/dotnet/api/system.func-3
- https://docs.microsoft.com/ja-jp/dotnet/api/system.predicate-1
- https://docs.microsoft.com/ja-jp/dotnet/api/system.comparison-1
- https://docs.microsoft.com/ja-jp/dotnet/api/system.converter-2