Visual Basic 2005 ここが便利!

第2回 型指定されたコレクションを実現するジェネリック

株式会社ピーデー 川俣 晶
2005/03/23
Page1 Page2

Visual Studio 2005や.NET Framework 2.0の登場とともに、プログラミング言語であるVisual Basic .NETも「Visual Basic 2005」へとバージョン・アップする。この新しいVisual Basicには、言語仕様の面でも統合開発環境の面でも、プログラミングを楽にする新機能が満載だ。本連載ではその中でも特に注目すべき便利な機能を1つずつピックアップしながら紹介していく。

楽がしたいと思って悪いか!? いや悪くない!!

Back Issue
1
“My”はクラスの海からVBプログラマを救う!?

 プログラマたるもの、楽がしたいと切実に思うのは義務であると思う。これは冗談でも何でもない。もちろん手を抜けといっているわけではない。同じ成果を出すなら、より少ない労力、より少ない時間で出した方がよいということである。より少ない労力や時間で成果が出せれば残業をしなくても済むし、上司から見れば生産性が上がったということになって好ましい結末である。

 さて、ここで問題なのは、より少ない労力や時間で成果を出す方法などあるのか、ということである。あらゆる場面でそれを実現する魔法などは存在しないが、条件や対象によっては確かに「可能」といえる。

 例えば、一例として、エラーの検出のタイミングという問題を取り上げてみよう。

 エラーには、コンパイル時に検出されるものと、実行時に検出されるものがある。この2種類、どちらに対処する方が楽だろうか。もちろん、コンパイル時に検出されるエラーの方が対処は簡単である。統合開発環境がソース・コード上のエラーの個所をすぐ教えてくれるし、たいていの場合、何が悪いのかもエラー・メッセージで明確に示されるので、修正方法もすぐ分かる。

 一方、実行時のエラーは原因が分かりにくいし、発生個所も明示されないことがある。具体的にソース・コード上のどの行が原因か分からなかったり、それが分かっても具体的にソース・コードをどう直せばよいかが分かりにくかったりする場合がある。

 しかも、この2つは、エラーを得るまでの時間が違う。コンパイル時のエラーはビルドを行えばすぐに見ることができる。しかし、実行時のエラーは、ビルドの後に実行しなければ見ることができない。実行直後に見られればまだよいが、場合によってはエラーを再現する手順を何段階も忠実に繰り返さなければ、エラー・メッセージを見られないかもしれない。また、その長い手順を間違えると最初からやり直しになるかもしれない。

 しかし、ここで「それは仕方がないよね。実行時エラーというのは、実行しないと出ないエラーなんだから」と思ってあきらめては「楽がしたいプログラマ失格」である。楽をするためなら、どんな努力もいとわない態度こそが重要なのである。もちろん、わずかな努力で大きな楽を手に入れるのが前提である。膨大な努力で、わずかな楽を手に入れても、それは楽とはいえない。

 実行時のエラーのうち、その一部は、コンパイル時にも検出が可能である。それは、プログラミング言語の設計や、その使い方次第といえる。また、プログラミング言語の進歩により、それまで実行時に検出されていたエラーの一部はコンパイル時に検出可能になる。つまり、より少ない労力、時間でエラーを見ることができ、楽ができるということである。

 以下に、新しいVisual Basic 2005でその一例を見てみよう。

実行時のエラーに泣け!

 Visual Basicで実行時のエラーになりやすいのが、型のミスマッチである。Visual Basicは、どちらかといえば型指定に関してルーズな言語である。どのような型のオブジェクトかを明示的に指定しなくてもコーディングでき、実行できる(「Option Strict On」とすれば明示的な指定を強制できるが、これはいまひとつ普及していないようである)。

 .NET Framework 1.1のコレクション関係のクラス(複数のオブジェクトの入れ物となるクラス)も、これと同様の特徴を持つ。しかし、型指定がルーズでも実行できるということは、正しい結果を出してくれるという意味ではない。実行が開始されても、何らかの間違いがあれば、実行中にエラーで停止するかもしれない。

 実際に、実行時に止まってしまうサンプル・プログラム(Visual Basic 2005 Express Editionベータ版で作成したコンソール・アプリケーション)を用意した。ここではコレクション・クラスの1つであるArrayListクラス(System.Collections名前空間)を利用している。

Module Module1
  Sub Main()
    Dim list As New System.Collections.ArrayList()

    list.Add("test")
    list.Add(New System.Text.StringBuilder("test"))

    If list(0).StartsWith("t") Then
      Console.WriteLine(list(0))
    End If

    If list(1).StartsWith("t") Then
      Console.WriteLine(list(1))
    End If

  End Sub
End Module
ArrayListクラスを利用したサンプル・プログラム
このプログラムはコンパイルできるが、実行時にエラーとなり停止する。

 このサンプル・ソースは、問題なくコンパイルを通り、実行を開始することができる。しかし、実行中に以下のようなエラー・メッセージを出力して停止してしまう。

Public member 'StartsWith' on type 'StringBuilder' not found.

 止まってしまう理由は簡単である。“test”はString型であり、この型はStartsWithメソッドを持っている。しかし、StringBuilderクラス(System.Text名前空間)はこのメソッドを持っていない。それ故に、

list(0).StartsWith("t")

は実行できるが、

list(1).StartsWith("t")

は実行できず、エラーとなる。

 このようなコードは、よほど間抜けな勘違いでもしなければ書かないと思うが、より複雑なソース・コードの中で、結果的に同じようなコードを実行してしまう可能性は十分にあり得るだろう。StringBuilderクラスは、String型の値を効率的に構築するために使うが、構築後にToStringメソッドを呼び出してString型の値を得るのをうっかり忘れる可能性は誰にでもあり得る。

コンパイル時にエラーを検出せよ!

 このエラーは、Visual Basic 2005の新機能であるジェネリック(Generics)という機能を使うことで、コンパイル時に検出できるようになる。つまり、楽ができるということである。

 具体的には、ジェネリック対応の新しいコレクション・クラスを使えばよい。ただそれだけである。

 もっと具体的にいえば、

System.Collections.ArrayList()

というクラス指定を、

System.Collections.Generic.List(Of String)

と書き換えるだけの話である。なお、Listクラス(System.Collections.Generic名前空間)は、新しい.NET Framework 2.0のクラス・ライブラリに追加されるArrayListクラスのジェネリック対応版である。

 書き換えを行った以下のサンプル・プログラムは、コンパイル時にエラーとなり、そもそも実行することができなくなる。

Module Module1
  Sub Main()
    Dim list As New System.Collections.Generic.List(Of String)

    list.Add("test")
    list.Add(New System.Text.StringBuilder("test"))

    If list(0).StartsWith("t") Then
      Console.WriteLine(list(0))
    End If

    If list(1).StartsWith("t") Then
      Console.WriteLine(list(1))
    End If

  End Sub
End Module
ジェネリック対応のListクラスを使って書き換えたサンプル・プログラム
このプログラムはコンパイル時にエラーとなるため、コーディング上のミスを事前に知ることができる。

 これは以下のようなコンパイル・エラーとなる。

型 'System.Text.StringBuilder' の値を 'String' に変換できません。 c:\GoodSample001\Module1.vb 6

 ここでポイントになるのは、

System.Collections.Generic.List(Of String)

と書かれた行の「Of String」という個所である。これは、

ここで宣言するコレクションのオブジェクトがString型を扱う

ということを明示している。それをコンパイラは理解しているので、もし、これにString型と互換性のない型の値をコレクションに追加しようとするコードがあれば、コンパイラはそれをエラーとして扱うことができるのである。

 具体的には、以下のコードがエラーになることを、コンパイラは理解できる。

list.Add(New System.Text.StringBuilder("test"))

 これで、実行時に検出されていた問題が、コンパイル時に検出できるようになり、労力と時間の節約が達成できた。しかし、それだけではない。コンパイル時の方が、より的確な問題の発生個所を検出していることに注目しよう。

 この事例の場合、String型の値を入れることを前提としたコレクションを使っていたわけで、バグの原因は上記の行にある。しかし、実行時のエラーは、その行ではなく、別の行しか教えてくれていない。その点でも、問題の個所を突き止める手間が減って、より楽ができたといえる。


 INDEX
  Visual Basic 2005 ここが便利!
  第2回 型指定されたコレクションを実現するジェネリック
  1.ジェネリックを使ってコンパイル時にエラーを検出せよ!
    2.型指定はクセになる/付録:ジェネリックを使ったクラスの自作
 
インデックス・ページヘ  「Visual Basic 2005 ここが便利!」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH