Option Strict On ノススメ
Option Strict
VB.NETにはOption Strict
ステートメントがあります。
暗黙的な型変換をコンパイル時に検出してくれるみたいですが、具体的にどんなことをやってくれるのか気になったので調べてみました。
困ったときのmsdn頼み
とりあえずmsdnの該当ページを見てみました。
暗黙的なデータ型変換を拡大変換だけに制限し、遅延バインディングを禁止し、Object 型になる暗黙の型指定を禁止します。
とあるので
- 暗黙的な縮小変換
- 遅延バインディング
- Object 型になる暗黙の型指定
の検出をやってくれるみたいですが、なんかよくわからない。
暗黙的な縮小変換
型変換と言えば、
- IntegerからLongなどの値の変換
- 参照型の他の参照型への変換
がありますね。
そのうち、IntegerからLongやサブクラスからスーパークラスなどの実行時に常に成功することが保障されている変換を拡大変換と呼びます。 逆にLongからIntegerやスーパークラスからサブクラスへなど、実行時に変換に失敗する可能性がある変換を縮小変換と呼びます。
具体例を挙げて見ていきましょう。
Option Strict On Class HelloWorld Public Shared Function Main(ByVal args As String()) As Integer Dim sourceInt As Integer = 1 Dim sourceLong As Long = 2L Dim targetInt As Integer Dim targetLong As Long ' こっちは常に成功する targetLong = sourceInt ' オーバーフローする可能性があり、実行時に変換に失敗する可能性がある ' したがって、これはコンパイル時にエラーとなる ' targetInt = sourceLong ' なので、変換を明示的に指示しなくてはならない targetInt = CInt(sourceLong) ' ちなみに、明示的に指示してもオーバーフローが発生した場合は ' OverflowException がスローされる Try Dim a As Integer Dim b As Long = 2147483648L a = CInt(b) Catch ex As OverflowException Console.WriteLine("Overflow") End Try Return 0 End Function End Class
IntegerよりLongの方がとりうる値が大きいのでIntegerからLongへの変換は常に成功します。 したがってLongへの暗黙的な変換はコンパイルに成功します。
逆にLongからIntegerの変換は値が消失する可能性があります。 したがってIntegerへの変換は明示的な指示する必要があります。 また、明示的に変換してもオーバーフローした場合はOverflowExceptionがスローされます。
次にスーパークラスとサブクラスの場合です。
Option Strict On Class HelloWorld Public Shared Function Main(ByVal args As String()) As Integer ' スーパークラスの変数にサブクラスの参照を代入することは可能 ' サブクラスはスーパークラスの属性を全て持っているから Dim p As Pet = New Cat() p.Eat() ' スーパークラスはサブクラスの属性を全て持っているとは限らないため ' 暗黙的な変換は失敗する ' Dim c As Cat = New Pet() ' 参照はスーパークラスの参照だが、実体はサブクラスなので ' 変換及び実行は成功する Dim c As Cat = DirectCast(p, Cat) c.Nyan() Return 0 End Function End Class Class Pet Public Sub Eat() Console.WriteLine("Eat") End Sub End Class Class Cat Inherits Pet Public Sub Nyan() Console.WriteLine("Nyan") End Sub End Class
Dim p As Pet = New Cat()
サブクラスはスーパークラスの属性を全て備えているため、縮小変換となり変換は常に成功します。 したがってコンパイル及び実行は常に成功します。
Dim c As Cat = New Pet()
逆にスーパークラスはサブクラスの属性を全て持っているとは限りません。 その為実行時に失敗する恐れがあるため明示的に縮小変換を行わなければなりません。
Dim c As Cat = DirectCast(p, Cat) c.Nyan()
例では参照そのものはスーパークラスの参照ですが、実体はサブクラスなので明示的な変換及び実行は成功します。
遅延バインディング
事前バインディングと遅延バインディング (Visual Basic)
Object型の変数にインスタンス参照が格納されたときに遅延バインディングされます。 そして、参照にたいして何らかの操作がされたとき実体にその操作が存在した場合は正常に実行され、存在しない場合は実行時エラーとなります。
Class HelloWorld Public Shared Function Main(ByVal args As String()) As Integer ' 実体に操作が存在するため、実行時に正常に実行される Dim p As Object = New Cat() p.Eat() ' 実体に操作が存在しないため、実行時に実行時エラーとなる Try Dim c As Object = New Pet() c.Nyan() Catch ex As System.MissingMemberException Console.WriteLine("MissingMemberException") End Try Return 0 End Function End Class ' Cat及びPetクラスの定義は上のコードと同じ
Option Strict On
の場合はこのような遅延バインディングを検出したらコンパイルエラーとします。
Object 型になる暗黙の型指定
変数の宣言に対するローカル型の推論の使用の有効・無効を切り替えるステートメントOption Infer
がOff
の場合、変数型を指定しない変数はすべてObject型の変数となります。
Option Strict On
の場合はこのようなObject型の変数宣言をコンパイルエラーとします。
Option Strict On Option Infer Off Class HelloWorld Public Shared Function Main(ByVal args As String()) As Integer ' Option Infer Offとなっているため型の推論が行われず ' その為Object型の変数とされる。 ' そのようなObject型の変数の宣言をOption Strict Onではコンパイルエラーとする。 ' Dim a = 1 ' 明示的に宣言する場合はコンパイルエラーとならない Dim a As Object = 1 Dim b As Integer = 1 Return 0 End Function End Class
わざわざ型推論を無効にする必要があるのかは疑問だが・・・。
まとめ
Option Strict On
にするとエラーチェックが強化され、実行時に実行時エラーが投げられる可能性が小さくなります。
その為、積極的に使用することをおすすめます。まぁ、タイトルがタイトルだからね。