|
|
連載
改訂版
プロフェッショナルVB.NETプログラミング
Chapter 13 オプション機能
株式会社ピーデー
川俣 晶
2004/08/19 |
|
|
4つのオプションのうち、まずはOption Explicit(explicitは“明示的な”の意)について説明しよう。といっても、すでに何度も取り上げているので、再度サンプル・プログラムを掲載することは、ここではしない。
まだ述べていない注意点は、VB 6とVB.NETで構文に違いがあることである。VB 6では、Option Explicit文の有無により機能の指定と無指定を区別できたが、VB.NETでは、Option Explicitの後に、OnまたはOffというキーワードを付け加えることでも区別可能である。
「もし、OnもOffも付けない場合は、Onであると見なされる」と、Visual Basic言語リファレンスに記述されている(古い版では誤ってOffであると記述されているので注意)。通常、VS.NETのIDEでコーディングしている場合は、“Option Explicit”と入力すると、自動的にOnが補われる。Onを削除した場合でも、自動的にOnが補われる。そのため、通常利用時には、特に省略時の値を意識する必要はないだろう。
Option Strict(strictは“厳密な”の意)は、VB.NETで新しく導入されたオプションである。Option Explicitと同様に、プロジェクトのプロパティとコード中でOnとOffを指定できる。プロジェクト作成時のデフォルトはOffである。本連載のこれまでのサンプル・プログラムは、すべてOption StrictがOffであることを前提としたものであった。では、これをOnにするとどうなるのだろうか? 以下の項目が禁止され、ビルド時にエラーになる。
- 明示的なキャスト演算子を使用しない縮小変換
- 遅延バインディング
- Object 型での=、<>、TypeOf〜Is〜、およびIs以外の演算
- 宣言でのAs句の省略
それぞれ、ピンとこない読者も多いと思うので、実例を示しながら違いを見ていこう。
明示的なキャスト演算子を使用しない縮小変換
例えば、リスト13-13のようなプログラムは、プロジェクト作成直後の設定のまま、普通に記述して実行することができる。特に問題は起こらない。
1: Public Class Form1
2: Inherits System.Windows.Forms.Form
3:
4: …Windows フォーム デザイナで生成されたコード…
5:
6: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
7: Dim a As Long
8: Dim b As Integer
9: a = 123
10: b = a
11: Trace.WriteLine(b)
12: End Sub
13: End Class
|
|
リスト13-13 Long型とInteger型の2つの変数を使用したプログラム
|
このソース・コードの先頭に次の1行を書き込んで、機能をオンにしてみるとどうなるだろうか。
Option Strict On
すると、ビルド時に以下のようなエラーが発生する。
1: Q:\aWrite\@it\vbn\022\smpl\Sample004n2\Form1.vb(51) : error BC30512: Option Strict On で 'Long' から 'Integer' への暗黙的な変換はできません。
|
|
リスト13-14 リスト13-13の先頭にOption Strict Onを書き込んだ場合に発生するビルド・エラー
|
このようなエラーが発生するのは、Long型の値をInteger型に代入しようとしているからである。Long型の方がInteger型よりも表現できる値の範囲が広いため、このような変数の代入は、オーバーフロー・エラーを発生させる可能性を持っている。代入される数値がInteger型で表現可能だと判断し、安全だと分かってこのような代入を意図的に書く場合もあるが、そうでない場合もある。例えば、変数を宣言するときに、間違えてLongのつもりでIntegerと書いてしまうこともある。そのような場合、ビルド時にエラーになれば、容易に書き間違いに気付くことができる。“Option Strict On”とは、後者のメリットを重視したモードである。
では、安全だと分かっているときに、どのように記述すればビルド・エラーが発生しないようにできるのだろうか? これは、キャストというものを行うことで回避できる。以下にキャスト機能を付加してビルド可能にしたプログラムを示す(リスト13-15)。
1: Option Strict On
2:
3: Public Class Form1
4: Inherits System.Windows.Forms.Form
5:
6: …Windows フォーム デザイナで生成されたコード…
7:
8: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
9: Dim a As Long
10: Dim b As Integer
11: a = 123
12: b = CInt(a)
13: Trace.WriteLine(b)
14: End Sub
15: End Class
|
|
リスト13-15 リスト13-13を、キャストを使用してOption Strict Onでもビルド可能にしたプログラム
|
このソース・コードの12行目のCInt関数を見ていただきたい。CIntはVB 6にも存在していたものだが、VB.NETでは特にキャストという役割を与えられている。CIntは引数の値を明示的にInteger型に変換する役割を持つ。これを記述することで、プログラマーは間違いなく、Long型をInteger型に変換するためにこの式を書いたことが明示される。
VB 6プログラマーならご存じのとおり、Integer型に変換するCIntのほかに、ほかの型に明示的に変換するCBool、CByte、CChar、CDate、CDec、CDbl、CLng、CObj、CShort、CSng、CStrといった関数が存在する。
クラス・ライブラリのクラスや、自作クラスのデータ型を変換する場合はどうだろうか。例えば、以下のようなソース・コードがあったとする。
1: Public Class A
2: End Class
3:
4: Public Class B
5: Inherits A
6: End Class
7:
8: Public Class Form1
9: Inherits System.Windows.Forms.Form
10:
11: …Windows フォーム デザイナで生成されたコード…
12:
13: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
14: Dim objA As A
15: Dim objB As B
16: objA = New B()
17: objB = objA
18: End Sub
19: End Class
|
|
リスト13-16 2つの自作クラスの間でデータ型の変換を行っているプログラム
|
これは問題なくビルドできるが、先頭行にOption Strict Onを書き込むと以下のようなエラーが発生するようになる。
1: Q:\aWrite\@it\vbn\022\smpl\Sample005n2\Form1.vb(58) : error BC30512: Option Strict On で 'Sample005n2.A' から 'Sample005n2.B' への暗黙的な変換はできません。
|
|
リスト13-17 リスト13-16の先頭にOption Strict Onを書き込んだ場合に発生するビルド・エラー(エラーとなっている58行目は、リスト13-16では17行目)
|
スーパー・クラスからサブ・クラスへの変換は、エラーとして扱われたことが分かるだろう(スーパー・クラスとサブ・クラスという用語の継承については、Inheritsステートメントによる継承機能を参照)。しかし、サブ・クラスからスーパー・クラスへの変換はエラーになっていない(16行目)。これは、何の情報の欠落もなく変換できるためである。しかし、あるクラスを継承したクラスは複数存在する可能性があるので、逆の代入はデータ型が整合するという保証はない。そのため、17行目はOption Strict Onではエラー扱いになっている。プログラマーが自分で確認して問題ないと分かっている場合は、CTypeまたはDirectCast関数を用いて、変換させたいという意図を明示的にソース・コードに書き込む必要がある。
1: Option Strict On
2:
3: Public Class A
4: End Class
5:
6: Public Class B
7: Inherits A
8: End Class
9:
10: Public Class Form1
11: Inherits System.Windows.Forms.Form
12:
13: …Windows フォーム デザイナで生成されたコード…
14:
15: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
16: Dim objA As A
17: Dim objB As B
18: objA = New B()
19: objB = CType(objA, B)
20: End Sub
21: End Class
|
|
リスト13-18 リスト13-16を、CType関数により明示的に型変換するように書き換えたプログラム
|
リスト13-18の19行目に書き込まれたCTypeが、明示的に変換を行う意図を示したものである。CTypeの第1引数が変換したい値である。第2引数は、変換結果となるべきデータ型である。こう記述すればビルド・エラーにはならない。
DirectCast関数を用いる場合は、CTypeの代わりにDirectCastと書き込む。CTypeとDirectCastの違いは、変換することができる対象範囲の違いである。CTypeは変換できるものなら何でも変換してくれる。しかし、DirectCastはクラス階層の下位方向への変換しか行わず、また値型も扱えないので、Long型からInteger型への変換などには使用できない。機能が少ない分だけ、DirectCastの方が高速に実行される。