連載:VB 6ユーザーのための
|
|
|
■統一感のある構造化例外処理とFinallyの落とし穴
今回、目的としている入力チェックのコードは取りあえずこれでうまく動くようになった。だが、先ほどのコードはどうも美しくない。同じコードが重複して登場している。
そこで、最後にコードをブラッシュ・アップしておこう。例外が起こったときの処理をCatch以下にまとめてしまえば、美しくなるはず。そこで、桁数チェックの部分で、商品コードが8桁でないときには、わざと例外を発生させることにする。それをCatchさせる(受ける)わけだから……そう、例外をThrowして(投げて)やればよい。大まかなロジックは次のようになるだろう。
Try |
Integer.Parseメソッドに、数字以外の文字が与えられた場合には、Exception型はException型でも、System.FormatException型がThrowされる。自分でThrowする例外はSystem.ApplicationException型を使えばよい。そうすれば、例外の種類によって処理を分けることができる。共通の処理はFinally以下に書けばいいので、次のようなコードになるはずだ。
|
|||||||||||||||
共通の処理をFinally以下にまとめた | |||||||||||||||
|
ところが、このコードはうまく動かない。実はFinally以下のコードは、Try〜End Tryブロックを抜けるときには、最後に必ず実行される。 で「Exit Try」を実行すると、そのままブロックの外に出るような気がするが、この場合もやはりFinally以下は実行される。 を「Exit Sub」に書き換えても同じ。従って、エラーでない場合にも、Finally以下が実行され、フォーカスの移動ができなくなってしまう。
普通、Finally部分は、使ったオブジェクトの解放などの後始末をするのに使う。Select CaseやFor〜Nextなどの感覚でとらえると違和感があるかもしれないが、途中で抜け出す場合にも必ずやっておかなくてはいけない後始末を書くわけだ。これも理にかなった仕様といえるだろう。
そんなわけで、共通の処理については、Subプロシージャにまとめるのがいい。今回は後始末は不要なので、Finally部分は書かなくてもいい。これは以下のリストを見るだけで十分理解できるだろう。
|
|
共通の処理をShowErrというプロシージャにまとめた | |
ShowErrメソッドの引数であるeとmsgは、呼び出し側で使っていたものをそのまま受け取っただけ。 |
結び − ちゃぶ台をひっくり返すようなお話
プログラミングの解説本や解説記事では、ステートメントの働きや処理の流れをできるだけ分かりやすく説明するため、流れを妨げる例外処理はあえて省かれることが多い。だが、現実の開発場面では例外処理にかける手間の方がはるかに大きいのではないだろうか。誌面に掲載されているサンプル・プログラムを流用するのはいいが、そこに書かれていない例外処理もきちんと書くようにしなければならない。
サンプル・プログラム程度であればOn Errorステートメントだけでも何とかなるが、実際には至る所で例外処理が必要になるので、その都度Try〜End Tryというブロックを作っておけば、コードがとても分かりやすくなる。もっとも、どのような例外が想定できるかはプログラミングの場面で初めて考えることではなく、仕様書を作る段階で漏らさずチェックしておくべきことなのだが。
今回は入力チェックや例外処理について見てきたが、これがすべてではない。例えば、フォームをすべて埋めてから[OK]をクリックした時点でチェックをすればいい場合もある。どういう例外処理が最適であるかは、フォームの使い方によっても変わってくるし、対象となるデータによっても変わってくる。
で、ここからちゃぶ台をひっくり返す話になるのだが、今回のプログラムも、実際にデータベースを検索するのであれば、検索が成功するかどうかを調べるだけでよく、文字列の長さやデータの種類を調べる必要などまったくないのである。本稿を読み進めている途中でそのことに気付いた人がいたとすれば、なかなかデキる人だと胸を張ってもいいと思う。もちろん、入力したデータが、データベースに記録されたり、後の計算に使われたりする場合には今回のようなチェックが必須なのはいうまでもない。例えば、払出数テキストボックスでの上限チェックなどは必須だろう。
また、今回は例外を多用したが、例外の発生にかかるオーバーヘッドは小さくないので、単純なIfステートメントでできるチェックよりも時間がかかる。今回のような対話型アプリケーションの場合はさほど問題になることはないだろうが、できる限り高速化したい場合には注意が必要だ*3。
*3 Integer型(=System名前空間のInt32構造体)にはParseメソッドのほかに、例外を発生させずに文字列を数値に変換するTryParseメソッドも用意されている。これについては「.NET TIPS:文字列字列を数値に変換するには?(TryParse編)」を参照。 |
今回のプログラムは、機能を理解するための「サンプルのためのサンプル」に近いものだが、そういう気付きも期待してあえてこの形にした。初めから正解だけを示しても、どういう間違いや落とし穴があるのか気付かないからだ。
さて、せっかくデータベースの検索フォームを作ったのに、入力チェックだけで終わってしまうのはあまりにも寂しい。が、さすがに読者の皆さんもお疲れだと思うので(書いている私もお疲れなので)、今回はここまでとして、次回、データベースの検索や更新を取り扱ってみたいと思う。
INDEX | ||
連載:VB 6ユーザーのためのこれならマスターできるVB 2005超入門 | ||
第4回 トラブルは水際で防げ〜入力時のチェックとエラー処理 | ||
1.サンプル・プログラム4 − データベース検索のためのダイアログ | ||
2.Validatingイベントを使って入力チェック | ||
3.構造化例外処理を使おう | ||
4.統一感のある構造化例外処理とFinallyの落とし穴 | ||
「これならマスターできるVB 2005超入門」 |
- 第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用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|
- - PR -