#author("2022-05-25T17:31:05+08:00","default:Admin","Admin") #author("2022-05-25T17:43:41+08:00","default:Admin","Admin") [[+C#+言語セクション]] #contents C#のラムダ式(Lambda)を紹介します。 *概要 [#te77db4b] ラムダ式は式とステートメントを含めることができる匿名関数であり、デリゲート型または式ツリー型を作成するために使用できます。~ ~ ラムダ式はラムダ演算子 => が使用され、この演算子を「~に入力」と理解します。 ラムダ演算子の左辺で入力パラメーターを指定し (ある場合)、右辺には式ブロックまたはステートメント ブロックが入ります。 => 演算子と代入 (=) は優先順位が同じで、結合規則が右から左です。~ ~ 使用するため、下記の名前空間が必要となります。 - using System.Linq; - using System.Collections.Generic; *書き方 [#e9024499] ラムダ式 x => x * x は、「x を x * x に入力」と読みます。この式は、次のようにデリゲート型に割り当てることができます。~ delegate int del(int i); static void Main(string[] args) { del myDelegate = x => x * x; int j = myDelegate(5); //j = 25 } ツリー型を作成するには ~ Expression<del> myET = x => x * x; *式形式のラムダ [#o72533e3] 右辺に式があるラムダ式を式形式のラムダと呼びます。 式形式のラムダは、式ツリー (C# および Visual Basic)の構築に幅広く使用されます。~ ~ - 式形式のラムダは式の結果を返します。基本的な形式は次のとおりです。 (input parameters) => expression - 括弧はラムダの入力パラメーターが 1 つの場合のみ省略可能で、それ以外の場合は必須です。 入力パラメーターが 2 つ以上ある場合は、括弧で囲んで各パラメーターをコンマで区切ります。 (x, y) => x == y -コンパイラが入力の型を推論するのが困難または不可能な場合もあります。 このような場合は、次の例のように型を明示的に指定できます。 (int x, string s) => s.Length > x - 入力パラメーターがないことを指定するには、次のように空のかっこを使用します。 () => SomeMethod() *ステートメント形式のラムダ [#xbaf2df1] - ステートメント形式のラムダは式形式のラムダに似ていますが、ステートメントが中括弧で囲まれる点が異なります。 (input parameters) => {statement;} - ステートメント形式のラムダの本体は任意の数のステートメントで構成できますが、実際面では通常、2、3 個以下にします。 delegate void TestDelegate(string s); … TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); }; myDel("Hello"); 匿名メソッドと同様、ステートメント形式のラムダを使用して式ツリーを作成することはできません。 *標準クエリ演算子でのラムダ [#z85701f4] 標準クエリ演算子の多くが、汎用デリゲートの Func<T, TResult> ファミリに属する型の入力パラメーターを持ちます。 Func<T, TResult> デリゲートは型パラメーターを使用して入力パラメーターの数と型、およびデリゲートの戻り値の型を定義します。 Func デリゲートは、ソース データのセット内の各要素に適用されるユーザー定義の式をカプセル化する場合に非常に便利です。 たとえば、次のデリゲート型を public delegate TResult Func<TArg0, TResult>(TArg0 arg0) このデリゲートを Func<int,bool> myFunc としてインスタンス化できます。int は入力パラメーター、bool は戻り値です。 戻り値は必ず最後の型パラメーターで指定されます。 Func<int, string, bool> は 2 つの入力パラメーター (int と string) と戻り値の型 bool を持つデリゲートを定義しています。 次の Func デリゲートを呼び出すと、入力パラメーターが 5 に等しいかどうかを示す true または false が返されます。 Func<int, bool> myFunc = x => x == 5; bool result = myFunc(4); // returns false たとえば System.Linq.Queryable で定義された標準クエリ演算子において、引数型が Expression<Func> の場合もラムダ式を使用できます。 Expression<Func> 引数を指定すると、ラムダは式ツリーにコンパイルされます。 標準クエリ演算子である Count メソッドを次に示します。 int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; int oddNumbers = numbers.Count(n => n % 2 == 1); 入力パラメーターの型はコンパイラが推論できますが、明示的に指定することもできます。 この特定のラムダ式は、2 で除算したときに剰余が 1 になる整数 (n) をカウントします。 次のメソッドは、配列 numbers 内の "9" の左側にある要素をすべて含むシーケンスを作成します。これは、"9" がシーケンス内で条件を満たさない最初の数値だからです。 var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6); 次の例は、複数の入力パラメーターを括弧で囲んで指定する方法を示しています。 このメソッドは、値がその位置よりも小さい数値が出現するまで配列 numbers に含まれるすべての要素を返します。 var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index); *使用例 [#ad1c053f] 下記のようなクラスがあります。 public class Person { public string Name { get; set; } public int Age { get; set; } } リストのオブジェクトを作成します。 List<Person> PersonList = <...>; **Sort [#m32e0318] リスト内の要素を並び替え PersonList.Sort((x, y) => { if (x.Age > y.Age) return -1; else if (x.Age == y.Age) return 0; else return 1; }); **Count [#u33b5a26] 指定する条件に満たす要素の個数を取得する #codeprettify{{ PersonList.Count(x => { return x.Age = 20; }); PersonList.Count( x => x.Age = 20 ); }} **Select [#q9eba2ce] 要素を新しい値へ射影する List<int>のオブジェクトをList<object>へキャスト #codeprettify{{ List<int> list = new List<int>(); //... list.Select(x => (object)x).ToList(); list.Select<int, object>(x => (object)x).ToList(); }} **OrderBy [#j21ac3f8] Dictionary<T> オブジェクトで例として説明します。 #codeprettify{{ Dictionary<Person, int> list = new Dictionary<Person, int>(); //「Person」クラスの「Name」プロパティの値による並ぶ list.OrderBy(key => (key.Key as Person>.Name)); //値による並ぶ list.OrderBy(key => key.Value); }} **Cast [#j21ac3f8] ListBoxのItemsをstring[] へ変換する #codeprettify{{ this.listBox1.Items.OfType<string>().ToArray() }} ** Distinct 去重 [#d9eda76d] Distinct 方法用来去除重复项。示例: #codeprettify{{ int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 }; var distinct = array.Distinct(); // distinct = { 1, 2, 3, 4, 5 } }} **イベントの実装に使用例 [#t3ea34b1] TextBoxの「TextChanged」イベントの実装例 this.textBox1.TextChanged += (x, y) => { this.textBox1.Text = "Changed"; }; #hr(); コメント: #comment_kcaptcha