連載:放課後VB教室

第3回 データ型の変換と遅延バインディングと絶品豆大福

羽山 博
2008/08/22
Page1 Page2

 私立関崇高校の大福研究会というナゾのサークルに所属する「サブロー」とクラスメイトの「ラスクちゃん」は、ひょんなことからVisual Basicのプログラミングを教えてもらうことになった。先生はサブローの先輩で、大学の先生でもある「ネスト先生」。前回は文字列型の変数との取り扱い方を学んだ。さてさて今回は……。

登場人物紹介はこちら

プロローグ 〜 宇宙の秘密と夏の妖怪!?

おかしいなぁ。さっきまでちゃんと動いていたプログラムが急に動かなくなっちゃったよ。コードは何も変えていないのに……。ん、なんだ、この音は? シャカシャカ、ザクザク。って、妖怪小豆洗い!? もしかして、エラーは妖怪のしわざ? だ、誰かいるのか!

はろー!

うわっ。なんでラスクがウチにいるんだよ。で、そのザル何? もしかして、お前、妖怪? あ、小豆洗いなのか? こっちに来るな!

さっきから何いってるの? 夏は水ようかん! 買ってきた水ようかんより、手作りの方がぜったいおいしいでしょ。作りに行くからって、昨日いったじゃない。玄関が開いてたから勝手に入っちゃったけど。サブローったら何度呼んでも返事しないから。で、このプログラムは何? 超球? 超体積? なんかのゲームなの?

あ、そうか、プログラムに集中してたから。これはネスト先生の命令で作ってるプログラム。なんでも宇宙の秘密を解き明かして、最高の大福を作るためのプログラムなんだとか。でも、いきなりコンパイル・エラーが出るようになったんだよ。「暗黙的な変換はできない」とか何とか。もしかして、ラスクなんかやった?

え、あたしは何も……、サブローがトイレに行ってる間に、どんなプロジェクトなのかなーって、プロパティとかいうのを見ただけ。

じゃじゃーん! 今日は、ついに群林堂の豆大福をゲットしたぞっ! あ、今日のお勉強のテーマは豆大福……じゃなくて、いまサブローくんが困っていることについてだ。

うわっ、ネスト先生までウチに! でも、ちょうどよかった。先生、この「暗黙的な変換はできません」ってエラーなんですが、いったいどういうことなんですか。

データ型は自動的に変換されるが……

じゃあ、どこまでプログラムを作ったか見せてごらん。うん、フォームはこんな感じか。


図1 デザインしたフォーム
  数値を入力するために使うテキストボックス(txtRadius)。
  計算結果を表示するためのラベル(lblVolume)。
  [計算(C)]ボタン(btnCalc)をクリックしたら、計算を実行し、結果を表示する。

 テキストボックスに入力された値を基に、計算結果をラベルに表示するだけだね。超球の超体積というのはn次元の球の体積のことだ。普通わたしたちが「球」というと3次元の球を思い浮かべるが、それをn次元に拡張したものだね。

 まあ、そんな難しいことは分からなくても、4次元の超球なら、半径を「r」とすれば、で体積に当たる値が求められる。4次元で体積っていうのもおかしいから超体積といってるけど。それで、コードはどうなってる。

超何とかの理屈はよく分からないんですが、要するに円周率を2乗したものに、半径を4乗したものを掛けて、2で割ればいいんですよね。こんなコードを書きました。ビルドしたときのエラー・メッセージも見てください。


図2 テキストボックスに入力された値を基に計算をするコード
コードに間違いはなさそうなのにエラーが出る。txtRadius.TextとVolumeがいけないらしい。

ははーん、そういうことか。サブローくんはエラー・メッセージ中にある「Option Strict On」って知ってるかな。

確か、データ型を厳密に取り扱うって設定ですよね。宣言のときにデータ型を必ず指定しなくちゃならないっていう設定で、例えば、


Dim Volume

だけだとエラーになるから、


Dim Volume As Double

のように宣言する必要がある、というやつですね。うーん、ちゃんと宣言してるんだけどなぁ。

確かに宣言は間違っていない。でも、Option StrictをOnにしたときの働きはそれだけじゃないぞ。

 Visual Basicでは特に何も指定しないと、自動的にデータ型が変換されるようになっているのは知ってるね。例えば、txtRadius.Textは文字列型(String型)だけど、ちゃんとDouble型に変換されて計算ができるし、VolumeはDouble型だけど、文字列型のlblVolume.Textに代入できる。だが、Option StrictをOnにしておくと、こういう型の不一致や精度の落ちる型変換がすべてエラーになるんだ。

でも、そもそもボクは「Option Strict On」なんてどこにも書いてないですよ。確か、コードの先頭に書いておくんじゃなかったでしたっけ?

じゃあ、メニューから[プロジェクト]−[<プロジェクト名>のプロパティ]を選択して、[コンパイル]タブをクリックしてごらん。この例だと、プロジェクト名はDaifuku3だから、メニューは[プロジェクト]−[Daifuku3のプロパティ]となるけど。

プロパティ、ですか。何となく犯人が分かってきたような……。えーと、こんな画面が表示されました。あ、Option StrictがOnになってる!


図3 プロジェクトのプロパティを表示する
[プロジェクト]−[<プロジェクト名>のプロパティ]を選択すると、プロジェクトのさまざまな設定を表示/変更できる。[コンパイル]タブでは「Option Explicit」や「Option Strict」の設定ができる。初期設定では、Option ExplicitはOn、Option StrictはOffである。

てへっ。知らないうちにあたしが設定を変えてたみたい。

なにが「てへっ」だよ。もうラスクったら。おかげでずいぶん無駄に悩んだじゃないか。コードとしてOption Strict Onと書く代わりに、ここで設定してもいいんですね。

いや、ラスクちゃんはお手柄かもしれないぞ。自動的にデータ型が変換されるのは便利なようで実はとても危険なんだ。プログラムは実行できても、思いもよらないエラーが起こる危険もある。

 エラーになればまだそこで見つかるからいいが、たまたまプログラムがちゃんと動いてしまって、正しくない結果が求められたりすると、とんでもないトラブルを引き起こしてしまうことだってある。だから、Option StrictはOnにしておく方が安全なんだ。

はぁ、そういわれればそうですよね。

うしし。また褒められちゃった〜。

ちなみに、コード中にOption Strictの設定を書いている場合は、プロパティの設定よりもコードの記述が優先される。じゃあ、Option StrictをOnにしているときにも正しく動くコードを書いてみよう。String型をDouble型に変換したり、Double型をString型に変換したりすればいい。

 それに、サブロー君のプログラムだと、数値と解釈されない文字がテキストボックスに入力されたときのチェックがないから、間違って英字を入力すると実行時にエラーになってしまう。エラー処理も併せて書いておこう。


Private Sub CalcVolume(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalc.Click

  Dim Volume As Double
  Dim Radius As Double

  If Not Double.TryParse(txtRadius.Text, Radius) Then
    MessageBox.Show("半径が正しく入力されていません")
    txtRadius.Focus()
    txtRadius.SelectAll()
    Exit Sub
  End If

  Volume = Math.PI ^ 2 * Radius ^ 4 / 2
  lblVolume.Text = Volume.ToString()

End Sub

修正されたサブローのプログラム
  TryParseメソッドでString型のデータをDouble型に変換する。エラーの場合にはメッセージを表示し、テキストボックス(txtRadius)に入力し直せるようにする。
  ToStringメソッドを使えばDouble型の値をString型のデータに変換できる。

 こんな感じかな。それにしても、Option Strict Onってのは、まさに群林堂の豆大福のような設定だな。お店の中できちんと手作り。添加物は一切使わないから、ヘンな粘り気もなくて、ああボクはいまこのとき大福を食べているだなぁ、としみじみと実感できる絶品の歯ごたえと甘み……。

はいはい。それはもういいですから。

ByRefで参照渡し

ねえねえ、ところでTryParseっていうのはデータ型を変換するメソッドなんだよね。なんだかこれまでのメソッドと違う感じ。普通、


Radius = Double.TryParse(txtRadius.Text)

のように書くと思うんだけど。

お、いいところに気が付いたね。話はそれるが大事なことだから見ておこう。

 TryParseメソッドを入力するときに引数のヒントがポップアップ表示されるから、それを見るとよくわかるんだけど、2番目の引数の渡し方が「ByRef」となっているよね。これは「参照渡し」の指定なんだ。


図4 TryParseメソッドの引数を入力する
2つ目の引数を入力するときにポップアップ表示されたヒントを見ると、「ByRef」となっていることが分かる。なお、メソッドの戻り値はBoolean型だ。

 参照渡しの場合は、変数の値そのものが渡されるのではなく、変数への参照が渡される。だから、呼び出されたメソッドでは、その参照を使って、呼び出した側の変数の値を変えてしまうこともできるというわけ。

 日常的な言葉でいえば、値渡しは「変数に入っている値のコピーを渡しますから、そのコピーを使って仕事をしてくださいね」ということで、参照渡しは「ここにある変数を直接使って仕事をしてくださいね」ということになるわけだ。値渡しの場合は受け取った値はコピーだから、それをいくら変えても元の値は変わらないけど、参照渡しの場合は……

変数の“ありか”を教えてもらったわけだから、そこにある値は元の値そのもの。だから値を変えると元の値も変わるってことね!

うむ、ラスクくんも分かってきたようだね。

なにを偉そうに……。で、TryParseメソッドの戻り値は、データ型の変換が成功したかどうかということを表すBoolean値だ。成功すればTrueが返されるし、失敗すればFalseが返される。

 もしデータ型の変換に失敗したら、Double型と見なせない文字列が入力されているということだから、メッセージを表示した後、txtRudiusのFocusメソッドを使って、テキストボックスに入力フォーカスを移し、SelectAllメソッドを使って、いまあるテキストをすべて選択している。つまり、再入力できるようにしているわけだ。

 ついでにいうと、最後のToStringメソッドには書式も指定できる。このままだと小数点以下がずらずらと表示されてしまうが、例えば、小数点以下を2けたにしたいときには、次のように引数で「"F2"」を指定しておけばいい。


lblVolume.Text = Volume.ToString("F2")


 

 INDEX
  放課後VB教室
  第3回 データ型の変換と遅延バインディングと絶品豆大福
  1.データ型は自動的に変換されるが……
    2.遅延バインディングって何?
 
インデックス・ページヘ  「放課後VB教室」


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