連載

改訂版
プロフェッショナルVB.NETプログラミング

Chapter 01 基本構文の変化

株式会社ピーデー 川俣 晶
2004/02/19

Page1 Page2 Page3 Page4

 本記事は、(株)技術評論社が発行する書籍『VB6プログラマーのための入門 Visual Basic .NET 独習講座』の一部分を許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。

 日付リテラルについての注意点

 ソース・コードに日付時刻を直接記述する場合は、日付リテラル形式(シャープ記号(#)で文字列を囲む)で記述するのが最も基本である。また、文字列で日付時刻を記述して日付型に変換する方法もある。これに関する若干の相違を説明する。まず、VB 6で書いたサンプル・プログラムをご覧いただきたい(リスト1-9)。

 1: Private Sub Form_Load()
 2:   Dim d1 As Date, d2 As Date
 3:   d1 = "2002/01/02"
 4:   d2 = #1/2/2002#
 5:   Debug.Print d1 = d2
 6:   Dim t1 As Date, t2 As Date
 7:   t1 = "01:02:03"
 8:   t2 = #1:02:03 AM#
 9:   Debug.Print t1 = t2
10:   Dim dt1 As Date, dt2 As Date
11:   dt1 = "2002/01/02 01:02:03"
12:   dt2 = #1/2/2002 1:02:03 AM#
13:   Debug.Print t1 = t2
14: End Sub
リスト1-9 日付リテラルと文字列を比較するプログラム

 これを実行すると以下のようになる。つまり、日付リテラルと、文字列から変換された日付の値は同じである。

1: True
2: True
3: True
リスト1-10 リスト1-9の実行結果

 一見、文字列を使った方は自然に年月日の順に並んで分かりやすく、日付リテラルは月日年の順に並んで不自然に見えるかもしれない。しかし、文字列から変換する場合の書式は、システムの国際化関連の設定により変化し得るもので、あるパソコンで正しく日付型に変換できたものが、ほかのパソコンで正しく変換できる保証はない。その点で、日付リテラルは、システムの設定にかかわらず目的の日付時刻を確実に記述できるので、より安全である。さて、このソースをVB.NET上で動くようにしたのがリスト1-11である。

 1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 2:   Dim d1 As Date, d2 As Date
 3:   d1 = "2002/01/02"
 4:   d2 = #1/2/2002#
 5:   Trace.WriteLine(d1 = d2)
 6:   Dim t1 As Date, t2 As Date
 7:   t1 = "01:02:03"
 8:   t2 = #1:02:03 AM#
 9:   Trace.WriteLine(t1 = t2)
10:   Dim dt1 As Date, dt2 As Date
11:   dt1 = "2002/01/02 01:02:03"
12:   dt2 = #1/2/2002 1:02:03 AM#
13:   Trace.WriteLine(t1 = t2)
14: End Sub
リスト1-11 リスト1-9をVB.NETで書き換えたプログラム

 これを実行すると以下のようになる。

1: True
2: True
3: True
リスト1-12 リスト1-11の実行結果

 日付リテラルの動作は変わっていない。VB.NETでも、やはり日付リテラルを使う方が安全といえる。その点でVB 6とVB.NETの間に相違はなく、変化はない。

 しかし、ここで問題なのはソース・コードの書式の違いではない。IDEで日付リテラルを入力しているとき、VB 6では年月日の順番で入力しても、システムが自動的に正しい順番に直してくれる。例えば「#2001/01/02#」と入力すると、自動的に「#01/02/2001#」に直してくれる。しかし、VB.NETのIDEはそのようなサービスを行ってくれず、自分で正しい順序に入力しなければならない。

 もし、正しい順序を正確に把握せずにVB 6で日付リテラルを使用していた場合は、VB.NETに移行する際には、正しい順序を頭に入れておく必要がある。時刻の方は24時間制で入力しても自動的に12時間制に直してくれるようなので、こちらは問題にならないだろう。

 変数の宣言をカンマ区切りで続けた場合の相違

 Dimステートメントで変数を宣言する際に、データ型を明示しない変数と明示する変数を同時に宣言すると、VB 6とVB.NETでは結果が異なる場合がある。以下にその例を紹介する。まずはVB 6で記述して正常に動作するサンプル・ソースを示す(リスト1-13)。

1: Private Sub Form_Load()
2:   Dim a, b As Integer
3:   a = 32768
4:   b = 1
5:   Debug.Print a + b
6: End Sub
リスト1-13 データ型を明示しない変数と明示する変数を同時に宣言しているプログラム

 これを実行すると以下の結果を表示する。

32769
リスト1-14 リスト1-13の実行結果

 このソースでは、aはVariant型、bはInteger型になり、Integer型には入らない大きな数32768をVariant型に代入することは何の問題もない。

 さて、次は同じソースをVB.NETで記述した場合である(リスト1-15)。

1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2:   Dim a, b As Short
3:   a = 32768
4:   b = 1
5:   Trace.WriteLine(a + b)
6: End Sub
リスト1-15 リスト1-13と同じ内容をVB.NETで記述したもの

 このソースでは、数値範囲を一致させるためにIntegerをShortに置き換えている(新しい整数型と整数型が表現できる数値範囲の拡大を参照)。これをビルドすると、以下のようなコンパイルエラーになる。

Q:\aWrite\@it\VB.NET\002\smpl\sample006n\Form1.vb(47) : error BC30439: 定数式は、型 'Short' では表現できません。
リスト1-16 リスト1-15をビルドしたときのコンパイルエラー

 エラーが起きたのは47行目と表示されているが、これはリスト1-15では3行目に当たる。3行目に記述された変数aはShort型であるため、32768を入れるには小さすぎるということがコンパイラにより指摘されたのである。2行目の変数宣言は、VB 6ではaの指定が省略されたと見なされてVariant型になるが、VB.NETではa、bの両方がShort型と見なされ、aのデータ型指定が省略されたとは見なされない。その結果、2つのソースは同じ意味を持つものとして扱われないことになる。

 このようなトラブルを回避するには、できるだけ変数のデータ型を明示的に付けるように習慣付ければよいだろう。

 変数のスコープ

 VB 6では、メソッド内で定義された変数は、メソッド内全域で有効であった。そのため、Forループの内側で宣言した変数をForループの外側で参照しても問題はない。また、宣言された場所に関係なく、メソッドを脱出するまでその内容は有効であり、値を累積することも可能だった。このことを示すサンプル・ソース(リスト1-17)と実行結果(リスト1-18)を以下に示す。

 1: Private Sub Form_Load()
 2:   Dim a As Integer
 3:   For i = 0 To 9
 4:     Dim b As Integer
 5:     a = a + 1
 6:     b = b + 1
 7:     Debug.Print a, b
 8:   Next
 9:   Debug.Print a, b
10: End Sub
リスト1-17 変数のスコープを示すプログラム
 
1             1
2             2
3             3
4             4
5             5
6             6
7             7
8             8
9             9
10            10
10            10
リスト1-18 リスト1-17の実行結果

 これをVB.NETに書き換えたものを以下に示す。

 1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 2:   Dim a As Integer
 3:   Dim i As Integer
 4:   For i = 0 To 9
 5:     Dim b As Integer
 6:     a = a + 1
 7:     b = b + 1
 8:     Trace.Write(a)
 9:     Trace.Write(", ")
10:     Trace.WriteLine(b)
11:   Next
12:   Trace.Write(a)
13:   Trace.Write(", ")
14:   'Trace.WriteLine(b) '名前 'b' は宣言されていません。
15: End Sub
リスト1-19 リスト1-17をVB.NETで書き換えたプログラム

 これを実行すると以下のようになる。

1, 1
2, 2
3, 3
4, 4
5, 5
6, 6
7, 7
8, 8
9, 9
10, 10
10,
リスト1-20 リスト1-19の実行結果

 ほとんど同じように見えるが、ソースの14行目がエラーになる点に注意が必要である。VB.NETでは、変数はスコープを持っており、Forループなどブロック構造を表記する構文の中で宣言された変数は、そのブロック構造の内側からしか利用することができない。しかし、変数にスコープを持つほかの主要な言語(C/C++/Java/C#など)とは異なり、メソッドなどを脱出するまで変数は有効という特徴は継承されており、ブロック内で宣言された変数で値を累積していくことができる。この点で、VB.NETのスコープの概念は、VB 6と異なるだけでなく、C/C++/Java/C#などとも異なるため、注意して扱う必要がある。

 値を累積したくない場合は、変数宣言に、例えば「Dim a As Integer = 123」のように初期化コードを必ず書き込むようにすると、意図しない動作を防止できる。


 INDEX
  [連載] 改訂版 プロフェッショナルVB.NETプログラミング
  Chapter 01 基本構文の変化
    1.型文字と新しいデータ型/整数リテラルと浮動小数点リテラル/文字リテラル
  2.日付リテラルについての注意点/変数の宣言をカンマ区切りで続けた場合の相違/変数のスコープ
    3.引数の値渡し(ByVal)と参照渡し(ByRef)のデフォルト/プロパティの参照渡し/可変長引数の参照と値
    4.省略可能な引数/Nothingの振る舞いの変更/行番号使用時のコロン(:)記号
 
「改訂版 プロフェッショナルVB.NETプログラミング 」


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