3流プログラマのメモ書き

元開発職→現社内SEの三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(vb.net)VB.NetではList.Findとかのデリゲートの実装が必要なメソッドは使えない!?

たとえばある List から特定の条件のものを探したいという時、今までは List をループでまわし、その中の条件式で探していました。

しかし、MSDNなど見てみると、

List.Find メソッド:指定された述語によって定義された条件と一致する要素を検索し、List 全体の中で最もインデックス番号の小さい要素を返します。

とか、

List.RemoveAll メソッド:指定された述語によって定義された条件と一致するすべての要素を削除します

など、よさげなメソッドがあります。最近まで、述語とはなんじゃらほいということで、調べもせず使ってませんでしたが、空いた時間にいろいろ調べてみると興味深いことが分かりました。

まず、MSDNでいう術語というはデリゲートのことで、このデリゲートを実装し、Find メソッドの引数に渡してやると、.NetのListクラスが渡されたデリゲートメソッドを実行するというからくりだそうです。普段のコーディングでも、あるメソッドを呼び出してそのメソッド内で条件により異なるメソッドを実行したいという時に、デリゲートを引数で渡してやれば、いちいちフラグとIF文で判定しなくて済むというメリットがありそうです。ま、デリゲートの詳しい話はいずれ。。

本題の List.Find 等にわたすデリゲートですが、VBの場合のサンプルとしてよくこういうのを見ます。

 
Public Shared Sub Main()
Dim dinosaurs As New List(Of String)
 
dinosaurs.Add("みかん")
dinosaurs.Add("リンゴ")
dinosaurs.Add("ブドウ")
dinosaurs.Add("給料")
 
 '検索
Dim strRes as String = dinosaurs.Find(AddressOf Search)
 
End Sub
 
'デリゲート(VBは匿名メソッドが使えないから別途定義しないとダメ)
Private Shared Function Search(ByVal s As String) As Boolean
If s = "給料" Then
Return True
Else
Return False
End If
End Function

これはばあるStringクラスの入ったリストから"給料"を探す時の例です。この場合、デリゲート内に、検索条件は固定(If s="給料" Then...)で記述しています。固定だと動的な条件に対応できないため実用価値はほとんどありません。

じゃあ、検索条件の文字列を変数化して、汎用的にしたいという場合はどうすればいいんでしょうか? その方法は不明です。ややこしいことをすればできるらしいのですが、お手軽に、というわけにはいかないようです。

しかし、実は同じ.Netでも C# には匿名メソッドたる機能があり、それを使うと動的な検索条件にも対応できるようです。 上記VBのソースを匿名メソッドを使ったC#で書きなおしたものです。

List list = new List();
list.Add("みかん");
list.Add("リンゴ");
list.Add("ブドウ");
list.Add("給料");
 
 
string strKey = "給料";
//匿名メソッドで検索
string result = list.Find(delegate(string s) {
return (s == strKey);
});

匿名メソッドはメソッド内にメソッドをかけるというもので、特に上記の例で重要なのは匿名メソッド内から上位スコープにアクセスできるという点です。上記の例だと呼び出し元メソッドで定義された、strKey変数を匿名メソッド内で参照できるのです。

これってめっちゃ便利じゃないですか? 別にメソッドを定義しないというだけでも楽ですが、上位スコープ変数にアクセスできるのは非常に助かります。

が、この匿名メソッドはVBとかC++には無いようです。これないと.Net自体が用意したデリゲートを定義しないと使えないメソッドのほとんどがあんま意味がないと思うのは自分だけでしょうか。

ああ、早くC#の開発したい。。

参考:

VB.NETと匿名メソッド