C#にはデリゲートという関数を変数のように扱う仕組みがあります。
変数のように扱えれば、関数の引数に関数を渡す事ができます。
引数に関数が渡せれば、計算式の一部だけを簡単に差し替える事ができます。
※デリゲートを更に詳しく知るには「C#のデリゲート (delegate) って何?」をご覧ください
汎用的なコードが作りやすいデレゲートですが、それを更に使いやすくしてくれるのが匿名メソッドです。
デリゲート(delegate)のおさらい
delegateを使ってコールバックをするサンプルを作ってみました。
以下の例は、List<int>を継承したクラスを作り、条件に合う項目だけを抜き出すWhereメソッドを作っています。この「条件に合う」という部分にdelegateを使って外に出す事で、様々な条件に対応できる汎用的なメソッドになります。
public delegate bool TestDelegate(int obj); public class TestList : List<int> { public TestList Where(TestDelegate func) { var list = new TestList(); foreach (var obj in this) { if (func(obj)) { list.Add(obj); } } return list; } }
以下はこのクラスを使う時のサンプルです。
public partial class TestWindow : Window { public TestWindow() { InitializeComponent(); var list = new TestList(); list.Add(0); list.Add(1); list.Add(2); var result = list.Where(TestFunc); } public bool TestFunc(int n) { if (0 < n) return true; else return false; } }
15~21行目で、定義した delegate の形のメソッドを作っています。
抽出条件はアプリケーション毎に色々なケースが考えられますが、その条件の部分だけを作るだけで抽出する部分のクラスやメソッドは汎用的になります。
デリゲートの煩わしさと問題点
上記の15~21行目にあたる部分ですが、コールバックされるメソッドを作る必要があります。
作ったメソッドが何度も使われるならいいですが、たった1度の為にわざわざ別のメソッドで作るのは煩わしいと感じます。何より、コールバックの部分だけ遠く離れたところにコードを書くことになるととても分かりづらいソースコードになってしまいます。
メソッドの中にメソッドを作るのが匿名メソッド
一番の問題はコールバック部分のコードが離れたところに書かれて分かりづらいという点です。
ならば、その場所に書いちゃおうというのが匿名メソッドです。
上記の例を匿名メソッドに変えてみると↓このようになります。
public partial class TestWindow : Window { public TestWindow() { InitializeComponent(); var list = new TestList(); list.Add(0); list.Add(1); list.Add(2); var result = list.Where( delegate(int n) { if (0 < n) return true; else return false; }); } }
12行目の、引数としてメソッド名を指定していた部分に直接メソッドを書き込んでいます。
メソッドの中にメソッドがある状態です。
メソッド名の代わりに、それがデレゲートだと分かるよう delegate と記述します。
1度きりしか使わないので、もはやメソッド名を付ける必要はありません。
名前が無いので匿名メソッドと呼ばれるわけです。
そしてラムダ式へ
これで少しデリゲートが使いやすくなりました。
ですが、削れる部分は削ってもっと簡素に記述したいと思うかもしれません。
それをやる仕組みがラムダ式です。
【=>】という記号を使い、書く必要のないコードを可能な限り減らします。
※ラムダ式を更に詳しく知るには「C#のラムダ式【=>】って何?」をご覧ください
関連記事
- C#の値型と参照型の違い
- C#のコンストラクタでオーバーロード
- C#のコンストラクタの継承
- C#のジェネリックを使おう
- C#のデリゲート (delegate) って何?
- C#のデリゲートお手軽にする匿名メソッド
- C#のラムダ式【=>】って何?
- C#で基底クラスのメソッドを置き換えるオーバーライド
- C#でキャストとas演算子を使いこなす
- C#で型を判別するtypeofとis演算子
- C#の値型でもnullを扱えるようにするNullable
- C#のリソース解放にはIDisposableとusingを使おう
- C#のStringとstring、Int32とint 違いは・・・ない!
- C#でasync/awaitを使った非同期処理
- C#で文字列を指定の区切り文字で分割
- C#のstring.Formatで桁数や書式を指定する
- C#の配列やListをソートする
- C#の配列やListを検索する (Find,FindAll,FindIndex)
- C#の配列やListを高速に検索する (BinarySearch)
- C#の配列の中に指定の要素が存在するかを調べる(LINQ Contains)
- C#の配列の中に条件を満たす要素が存在するかを調べる(LINQ Any)
- C#の配列から条件に合う要素を抽出する(LINQ Where)
- C#の配列で要素毎の処理結果を得る(LINQ Select)
- C#の配列を並び替える(LINQ OrderBy,ThenBy)
- C#の配列をグループ毎に処理する(LINQ GroupBy)
- C#の配列を内部結合(INNER JOIN)する(LINQ Join)
- C#の配列から最初の要素を取り出す(LINQ First,FirstOrDefault)
- C#の配列の重複要素を削除する(LINQ Distinct)
- C#でフォルダ内のファイル名一覧を取得する
- C#でテキストファイルを読み込む
- C#でテキストファイルに書き込む
- C#でバイナリファイルを読み込む
- C#でバイナリファイルに書き込む
コメントをお書きください