前回はGetValue3メソッドの引数にLenCheckのdelegateを受ける実装を行ったので,今回は,どうやってdelegateを渡すかというところやって行きたいと思います。
GetValue3メソッドを呼び出す方法
まずは,button3_ClickイベントからGetValue3メソッドを呼び出すように書いてみましょう。GetValue2としていた部分をGetValue3に変更します。
private void button3_Click(object sender, EventArgs e) { var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" }; var result = GetValue3(values, ここをどうやってわたすか); Console.WriteLine(string.Join(",", result)); }
GetValue3の第1引数はstring配列なので,これまでと変わりませんが,第2引数は,delegateになっているため,「ここをどう書くか」というお話をしていきます。delegate引数の渡し方は,いくつか書き方がありますが,まずは一番簡単な方法からやっていきましょう。
メソッドでdelegateを渡す方法
一番簡単な方法は,メソッドでdelegateを渡す方法です。
もう一度定義したdelegateを見てみましょう。
delegate bool LenCheck(string value);
stringを投げたらboolを返すという定義でしたね。delegate引数には,この「stringを投げたらboolを返す」という定義と同じ定義のメソッドを作成し,そのメソッド名を渡すことで,delegate引数に渡すことができます。
メソッドは例えば次のような感じで書きます。
private bool Shiki1(string value) { return ; }
戻り値がboolで,引数がstring 1つになっていればOKです。メソッド名は何でも構いません。今回はShiki1としています。こんな感じで引数と戻り値を,delegateであるLenCheckに合わせておけば,LenCheckとして引数に使うことができます。
当然このメソッドは戻り値がboolなわけですから,何かしらboolを返却してあげる必要があるわけです。ここで何を返却するかというと,これまで言ってきたように,「>=3
」や,「==3」など,「どういった判定をするか?」という部分を記述すればいいわけです。今回は「value.Length == 3」とすることで,文字列が3文字の文字列の場合のみTrueが返却されるように実装しています。ちなみにメソッドの中身は,何行でも構いません。今回は1行になっていますが,複数行でももちろんOKです。普通のメソッドなので,とにかくboolを返却していれば問題ありません。 こんな出てきたらこのメソッドの名前「Shiki1」を,GetValue3の第2引数に設定すればOKです。
private void button3_Click(object sender, EventArgs e) { var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" }; var result = GetValue3(values, Shiki1); Console.WriteLine(string.Join(",", result)); }
GetValue3の第2引数に,「ここをどうやってわたすか」と記載していましたが,Shiki1に変更しました。これでコンパイルエラーが消えているはずです。
このように記載するとGetValue3を 呼び出した時に,Shiki1が,GetValue3のlenCheckに 渡ることになるので,その中で使われているif文のlenCheck(val)の部分は,「==3」かどうかで判定した結果のboolが返却されることになり,結果としては,3文字の文字列のみが出力されることになります。
private void button3_Click(object sender, EventArgs e) { var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" }; var result = GetValue3(values, Shiki1); //このShiki1がlenCheckに渡る Console.WriteLine(string.Join(",", result)); } //↓ ここに渡る 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(); }
実行
実行してbutton3を押下します。
3文字である「CCC」のみが出力されることが確認できます。
これでShiki1の3文字かどうかのチェックが行われているということが確認できます。
別の式を投げる
同じ要領で別の式を投げるということも当然できます。デザイン画面でボタンをもう1つ追加しましょう。
button4を画面に追加したら,ダブルクリックをして,クリックイベントを自動生成します。
button4_Clickイベントに次のように記載し,さらにShiki2メソッドを作成し,それを呼び出すようにします。
private void button4_Click(object sender, EventArgs e) { var values = new string[] { "A", "BB", "CCC", "DDDD", "EEEEE" }; var result = GetValue3(values, Shiki2); Console.WriteLine(string.Join(",", result)); } private bool Shiki2(string value) { return value.Length >= 4; }
Shiki2メソッドは4文字以上の時にTrueを返却するように実装しました。Shiki2を呼び出しているbutton4_Clickでは,4文字以上の文字列だけを出力するようになるはずです。
実行
実行してbutton4を押下します。
4文字以上の文字列のみが表示されていることが確認できます。
ポイントは,button3_Clickもbutton4_Clickも,GetValue3を呼び出しているのですが,delegateであるLenCheckの部分にShiki1を渡すか,Shiki2を渡すかの違いで,GetValue3にどういった判定をさせるかを変化させているということです。delegateを使うことで,引数に「式」を投げることに成功しているということです。これにより,今までの値を引数にするということに加えて式(メソッド)を引数にすることが可能であるということが理解していただけたと思います。ラムダ式を理解するうえで,このdelegateによる式を引数にするという考え方が,非常に重要な考え方になります。
delegateはC#1.0からある機能なのですが,C#2.0,C#3.0と進化するなかで,delegateというキーワード自体は,直接書かなくても,プログラミングできるようにはなってきていますが,すべての根底にはこのdelegateがあり,そこからラムダ式までの道が続いているので,ここまでが理解できていないようであれば,復習をして,ここまでがしっかり理解できた状態で,次に進んでください。こういった技術書は,途中でつまずいてしまうと,その後が理解できなくなり,読むのをやめてしまうことになります。私も分厚い本を途中で挫折した経験が何度もあります。そういった失敗を分析すると,必ず,途中で何かを見失っているということです。理解しないまま進むと,その先はさらに理解できず,いやになってやめてしまいます。本書はつまずくほど分厚い本ではないので,最後まで読み続けていただけると思いますが,焦らずにゆっくりと読んで,1つずつ,しっかり理解するのが,完読するコツだと私は思っています。
#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_カスタムクラスのコレクションに対するラムダの書き方