前回は引数に応じた桁数以上の文字列が取得できるメソッドを作成しました。string配列と桁数を引数にすることで,ある程度汎用的に使えるメソッドにはなりました。
比較の部分も引数にできる?
ここまでで,比較対象の文字列と,桁数までを引数にしたので,そのあたりは柔軟にチェックできるメソッドにはなりました。しかし,比較する部分は固定になっていますよね。
if文の大なりイコール「>=」の部分です。
private string[] GetValue2(string[] values, int len) { var result = new List(); foreach (var val in values) { if (val.Length >= len) { result.Add(val); } } return result.ToArray(); }
この大なりイコールの部分をイコール「=」にしたり,小なりイコール「<=」にしたりすることは現状できていません。この演算子の部分,判定の部分の「式」を引数に与えることができるようにC#では設計されています。
配列や変数,数値などを引数にするという発想は私のような凡人にも思いつきますが,「式」を引数にするという発想はなかなか思いつくものではありません。「こういった発想力のあるプログラミング言語の開発者の方々は凄いな」と感心させられますが,ラムダ式を習得するには,その前にこの「式」を引数にするという発想を身に着けないといけません。その式を引数にするために必要な知識がdelegate(デリゲート)になります。
「式を引数」にするという表現をしましたが,「メソッドを引数にする」と表現した方がわかりやすいかもしれません。この「メソッドを引数にする」ために必要なのが,delegateです。
ボタンの追加
新たにボタンを追加します。
クリックイベントの作成
追加したボタンをダブルクリックで,クリックイベントを自動生成し,その中に,button2_Clickの中身をコピーペーストします。
//デリゲート //delegate private void button3_Click(object sender, EventArgs e) { var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" }; var result = GetValue2(values, 4); Console.WriteLine(string.Join(",", result)); }
button3_Clickイベントは現状,button2_Clickイベントをコピーしてきたため,4文字以上の文字列を取得するようなロジックになっています。デリデートの書き方を学ぶために,「3文字イコール」の文字列のみを取得するようなロジックにするにはどうすればいいかを考えてみましょう。GetValue2のメソッドは「val.Length >= len」となっているため,引数で3桁と指定しても,3桁以上の文字列が取得されてしまいます。今回はデリデートを使って,「>=」の部分が「==」で判定されるためにはどうすればいいかを考えていきます。
これから何がしたいのか?
これから何がしたいのかというと,GetValue1で「val.Length >= 3」となっている,判定の部分を外から投げたいわけです。intやstringのように,引数で,判定方法を投げたいというわけです。「>= 3」の部分を,「== 3」や「== 4」,「<= 4」など,自由に判定方法を投げたいわけです。その判定のための「型」がデリデートであり,stringを渡したら,boolが返るという,「型」になるわけです。
この解説だけだと意味がわからないかもしれないですが,実際に書いていけば理解できると思うので,実際に実装して行きます。
delegateの書き方
それではまず実際にdelegateどういった感じで書くかというのを実際にやっていきたいと思います。
例えばこんな感じです。
delegate bool LenCheck(string value);
まず最初のdelegateの技術はこれがdelegateであるということを示すキーワードです。先述のように式やメソッドを引数にしたいという場合は,delegateを使うので,そういった場合はこのdelegateキーワードを使います。
続いてdelegateより後の「bool LenCheck(string value);」の部分は,普段メソッドで書いている「戻り値」「メソッド名」「引数」の部分だけを定義します。ボタンクリックイベントや,通常作るメソッドなどでは,戻り値を書いて,メソッド名を書いて,引数を定義しますが,それの定義の部分だけを書いています。 要するにこれは,戻り値がboolで,引数が「string」1つの,LenCheckという名前のdelegateという意味になります。
もちろん戻り値は何でもいいですし,戻り値がない場合はvoidになります。
引数は「無し」でもいいですし,1つでも,2つでも,もちろんstring以外のどのような型でも問題ありません。
メソッドの作成
先程delegateを作成したので今度はそれを使うメソッドを作成してみます。
まずは,以前作成した,GetValue1をコピーペーストし,新たにメソッドGetValue3を作成します。
private string[] GetValue3(string[] values) { var result = new List(); foreach (var val in values) { if (val.Length >= 3) { result.Add(val); } } return result.ToArray(); }
今回,delegate版のメソッドで実現したいのは,「val.Length >= 3」の判定の部分を,外から投げられるようにしたいわけなのですが,そういった場合に,ここで先ほど作成したdelegateを使うことになります。 このために先ほどはstringを投げたらboolを返すという定義だけを作ったわけです。
作成したdelegateを使用する
private string[] GetValue3(string[] values, LenCheck lenCheck) { var result = new List(); foreach (var val in values) { if (lenCheck(val)) { result.Add(val); } } return result.ToArray(); }
まずは引数にdelegateであるLenCheckを受けるようにしています。これは先ほど作成したdelegateですね。大文字のLenCheckはdelegateの型を表していて,小文字のlenCheckはdelegateの変数名を表しています。これでstringを投げたらboolを返すという定義が引数に渡るようになるわけです。
実際にこのメソッド内で使用するのは子文字のlenCheckの方です。これがdelegateの変数名になっているわけですから。
これをどこで使うかですが,if文箇所で使います。もともと3文字以上などの「>=3」などと書いていた部分,ここの定義を外部から渡したいわけなので,ここで小文字lenCheckを使います。それだけではコンパイルが通りません。
なぜかというとこの定義は「stringを受けてboolを返す」という定義になっているので,stringを渡してあげないといけないわけです。
そうしないと,コンパイルエラーになります。この場合のstringは何でしょうか?...
foreachで回している「val」ですね。
このvalに対してのチェック方法を,外部から投げているわけなので,「stringを投げたらboolを返す」という定義の,投げるべきstringはvalになるわけです。
なので,今回引数に追加したlenCheckに「>=3」や「==3」などの式を投げつけることで,このvalがどのように判定されるかを変化させることができるわけです。
ではどうやって投げつけるか?というお話は次回にしたい思います。
#02_プロジェクトの作成
#03_ラムダなしで実装
#04_ラムダなしで実装_共通関数
#05_ラムダなしで実装_引数追加
#06_delegateを定義する方法
#07_delegateの使い方
#08_delegate_引数2つ
#09_匿名メソッドの使いかた
#10_Predicateの使い方
#コラム_C#の歴史とここまでのまとめ
#11_ラムダ式の書き方
#12_ラムダ式の実装
#13_FuncとActionとは
#14_Funcの実装とラムダ式複数パラメータの書き方
#15_ラムダの右辺が複数行の時の書き方
#16_Actionのパラメータありの実装
#17_Actionのパラメータありとラムダ式の書き方
#18_Actionのパラメータなしと引数なしのラムダ式の書き方
#19_コレクションに対する代表的なラムダ式の書き方
#20_カスタムクラスのコレクションに対するラムダの書き方