LoginSignup
16
18

More than 3 years have passed since last update.

[VB.NET] 型変換/キャストのまとめ ―どう使い分ければいいのか?

Last updated at Posted at 2019-12-11

明示的な変換(キャスト)

キャスト演算子

C# のキャスト演算子 () に相当するものは VB.NET にはない。

DirectCast 演算子

  • Object 型とほかの型との変換において、VBランタイムヘルパーを使用しない分、CType 関数より高速に動作する。
  • 値型と Object 型の間の変換にはボックス化、ボックス化解除が使われる。異なる型へはボックス化解除できず、暗黙の型互換があっても InvalidCastException が発生する。
  • 実行時の型が変更後の型と一致しないとキャストに失敗する。たとえば、Integer 型から String 型へは変換できない。
  • C# のキャスト演算子 () と異なり、暗黙の型互換があっても変換できない。たとえば、Integer 型から Long 型への変換はコンパイルエラーとなる。

TryCast 演算子

  • 参照型のみ。
  • C# の as 演算子に相当。IL の isinst 命令 にコンパイルされる。
  • TypeOf ... Is ... で判定してから DirectCast するのは変換が二度生じて無駄である。TryCast してから IsNot Nothing 判定する方がパフォーマンスがよい。
改善前
If TypeOf obj Is T Then
    Dim casted = DirectCast(obj, T)
     :
End If
改善後
Dim casted = TryCast(obj, T)
If casted IsNot Nothing Then
     :
End If

余談

IsNot Nothing に関し、『コーディング規則 - Visual Basic | Microsoft Docs』に

IsNot の代わりに Not...Is Nothing キーワードを使用します。

とありますが、誤訳ですのでご注意ください
わざわざ VB2005 で追加したわけだし、「IsNot 演算子の方が否定対象が明確でいいのになあ」と思い、念のため英語ページ をあたったところ、

Use the IsNot keyword instead of Not...Is Nothing.

と全く逆になっていました。

フィードバックすべきか、と思ったらクローズが1件あったので、開いてみると、@tfukumori さんが別の箇所(HandlesAddHandler)に関して同様の指摘をされていて、なんと、

現在、機械翻訳されたコンテンツに対する翻訳の問題へのコントリビューションはできません。

という回答で終わっていました。
こんな初歩的・根本的な誤りを放置されるとは…やはり機械翻訳は参考程度に見た方がいいですね。

CType 関数

  • Object 型とほかの型との変換において、Microsoft.VisualBasic.CompilerServices.Conversions クラス のようなVBランタイムヘルパーを使用する分、DirectCast よりパフォーマンスは落ちる。
  • コンパイラによってインライン展開されるため、VBランタイムヘルパーが使用されない場合のパフォーマンスはよい。
  • 暗黙の型互換があれば変換できる。暗黙の型互換がない場合、たとえば Integer 型から DateTime 型への変換はコンパイルエラー、Object 型にボックス化された Integer 値から DateTime 型への変換は実行時に InvalidCastException となる。
  • VB.NET の CType 関数と C# のキャスト演算子とでは、結果が異なる場合がある。たとえば Single 型から Integer 型に変換する場合、CType 関数では小数点以下を銀行型丸め(近い方の整数に、半整数 .5 は偶数になるように丸める)によって取り除くが、C# では切り捨てられる。

データ型変換関数(CStr, CInt, ...)

  • CInt(obj)CType(obj , Integer) は等価(ほかの型についても同様)。
  • CInt の小数→整数は銀行型丸め。

ヘルパークラス/メソッドによる変換

Parse, ParseExact, TryParse, TryParseExact メソッド

  • 文字列から変換。
  • DateTime 型の場合、ParseExact で書式を明示指定して変換することができる。
  • Nothing を渡すと ArgumentNullException が発生する。

ToString メソッド

  • 文字列化。
  • EnumToString() はメンバ名になる。
  • DecimalToString で末尾のゼロを取り除く(1.0"1")には、書式 "G29" を指定する。(.NET 1.1 以上の場合)

Convert クラス

  • 基本データ型を別の基本データ型に変換する。
  • 内部的に Parse メソッドを呼んでいる。
  • 小数から整数への変換は銀行型丸め。

TypeConverter クラス

  • コントロールのデザインプロパティの文字列解析などに使用されている。
  • TypeDescriptor.GetConverter(Type) メソッドで、実行時に型(Type オブジェクト)を指定して TypeConverter オブジェクトを取得することができる。
  • 文字列からの変換に ConvertFromString(String) メソッドが用意されているが、既定で用意されたコンバーターの許容範囲は狭い。桁区切りカンマ、通貨記号、全角は数値の構成要素として解釈されず、小数から整数へのキャストもできない。

Microsoft.VisualBasic.Conversion.Int メソッド

  • 負の値で切り捨てにならない。負でも切り捨てるには Fix 関数を使う。

Microsoft.VisualBasic.Conversion.Val メソッド

  • VB6時代から想定外の挙動で何かと問題を引き起こしてきた。Val("1,234") の結果は Double1 である。
  • 手軽で許容範囲が広い反面、意図しない変換結果になることがあるので、使用には注意が必要。

暗黙的な変換

暗黙の数値変換(.NET 共通)

  • 暗黙的に変換可能な型の対応が「.NET の型変換の表 | Microsoft Docs」に拡大変換/縮小変換と分けて記載されている。
  • 拡大変換の多くは情報を失うことなく実行できるが、浮動小数点数値型への変換では精度が損なわれるケースもある。
  • 縮小変換では情報が失われる可能性がある。変換元の値が変換先の型の MaxValueMinValue の範囲外にある場合は OverflowException が発生する。
  • Integer のリテラル、定数値が変換先の型の範囲内にある場合、暗黙的に変換できる。範囲外の場合はコンパイルエラーとなる。

Option Strict Off

  • Off だと意図しない型変換が暗黙的に行われ、バグの温床になる。On にすることが推奨されている。
  • 既定は Off なので、プロジェクトを作成したら [コンパイル オプション] 設定で On にするのを忘れないようにする。
    • たまに忘れて後で気づく。VB6からの移行を考慮してのことなのかもしれないが、そろそろプロジェクトの既定は On に変えてほしい。
16
18
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
18