【実務・中級編】初心者向け:VB.NETのCInt・CLngとVal関数の挙動差異:レガシーな数値変換からモダンなTryParseへの移行 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

【VB.NET極限講座】文字列数値変換の罠:CInt・CLng・Valを捨て、なぜTryParseへ移行すべきなのか

業務自動化ツールや社内ニッチシステムの開発現場において、画面入力、CSVファイル、あるいは外部APIから取得した「数字の形をした文字列」を数値型(IntegerやLong)へ変換する処理は、避けて通れない基本中の基本だ。

しかし、この「文字列から数値への変換」こそが、運用フェーズに入ってからアプリを突然クラッシュさせたり、誰も気づかない裏でサイレントなデータ破損を引き起こしたりする「地雷原」であることをご存知だろうか。

今回は、VB.NETの歴史的背景を引きずったレガシーな変換関数(`CInt`, `CLng`, `Val`)の危険な挙動の差異を解剖し、プロの現場でスタンダードとされる安全・堅牢な `TryParse` パターンへの移行術を、チーフアーキテクトの視点からロジカルかつシャープに伝授する。

1. レガシー関数たちの正体:なぜそれらは「使ってはいけない」のか

VB.NETには、数値を変換するための手段がいくつか用意されている。だが、それぞれが孕んでいる「リスク」の本質を理解している開発者は意外と少ない。まずは、旧来の関数たちが持つ致命的な癖を整理しよう。

① `CInt` / `CLng` (型変換関数)

これらはVB6時代(あるいはそれ以前)の互換性を色濃く残した、VB.NETの組み込み関数(Microsoft.VisualBasic命名空間)である。

  • 挙動: 引数に渡された文字列が有効な数値であれば変換する。
  • 最大の罠: 「変換できない文字列(例: `”123A”`, `””`, `Nothing`)」や「オーバーフロー(Integerの表現限界を超える値)」を渡すと、容赦なく例外(`InvalidCastException` や `OverflowException`)をスローしてアプリケーションが異常終了する。
  • アーキテクトの視点: ユーザーが画面のテキストボックスに誤ってスペースや文字を入力しただけでアプリが落ちる設計など、プロダクション環境では論外である。

② `Val` 関数

`Val` もまた、Visual Basic特有のレガシー関数である。C言語の名残りや簡易的なスクリプト言語のような挙動を示す。

  • 挙動: 文字列の先頭から数値とみなせる部分だけを読み取り、数値に変換する。途中で数値以外の文字(アルファベット等)が出てきたら、そこで解析を打ち切る。
  • 具体例:
  • `Val(“123円”)` ➔ `123` (エラーにならない)
  • `Val(“ABC123”)` ➔ `0` (先頭が文字なので0を返す)
  • 最大の罠: 「エラーを絶対に吐かない代わりに、勝手に都合よく解釈して誤った数値を返す(サイレント・エラー)」。

金額や数量を扱う業務システムにおいて、ユーザーが誤入力した `”1,230円”`(ロケールによってはカンマが文字扱いされる等)や、データベースのキー値が途中で途切れた文字列を `Val` で処理した場合、「エラーにならないせいで、気づかないうちにデータベースのデータを破壊(誤った値で更新)した」という最悪のバグを引き起こす。

2. 【比較表】数値変換アプローチの決定版マトリクス

| 関数 / メソッド | 不正な文字列の挙動 | オーバーフロー時の挙動 | 空文字列 (`””`) / `Nothing` | 業務システムでの評価 |
| :— | :— | :— | :— | :— |
| `CInt` / `CLng` | 例外発生(即クラッシュ) | 例外発生(即クラッシュ) | 例外発生 | × 絶対NG(例外制御は重い) |
| `Val` | 無視して手前まで抽出 / `0` | 倍精度浮動小数点(Double)で処理 | `0` | × 絶対NG(意図しない値に化ける) |
| `Integer.TryParse` | `False` を返す(安全) | `False` を返す(安全) | `False` を返す | ◎ 推奨(モダン・堅牢) |

3. モダンの極意:`TryParse` による堅牢な設計

.NET Framework / .NET Core 世代における正解は、各数値型(`Integer`, `Long`, `Decimal` など)が持つ `TryParse` メソッド を利用することだ。

`TryParse` は、例外(Exception)という重い処理コストを発生させず、戻り値の真偽値(Boolean)によって「変換成功か、失敗か」を优雅(エレガント)に判定する。また、変換に成功した値は `ByRef` 引数(`Out`変数)を通じて安全に取得できる。

プロダクションコード例:安全なデータ処理のイディオム

以下に、ファイル読み込みや画面入力値の検証において、保守性が高くバグの起きない模範的な実装コードを示す。

Imports System

Public Class NumberConverterSample

Public Sub ProcessUserInput(ByVal rawInput As String)

Dim parsedValue As Integer

‘ TryParseパターンのイディオム
‘ 戻り値が True なら変換成功。False なら不正な値。
If Integer.TryParse(rawInput, parsedValue) Then
‘ — 【成功系】安全に数値として処理を継続 —
Console.WriteLine($”変換成功: {parsedValue}”)

‘ ビジネスロジックの実行
ExecuteBusinessLogic(parsedValue)

Else
‘ — 【失敗系】アプリを落とさず、適切なハンドリングを行う —
‘ ログ出力、ユーザーへの入力促し、デフォルト値の適用など
Console.WriteLine($”[警告] 不正な入力値が検出されました: ‘{rawInput}'”)

‘ 必要に応じて例外を投げるのではなく、業務エラーとしてハンドリングする
‘ Throw New BusinessException(“正しい数値を入力してください。”)
End If

End Sub

Private Sub ExecuteBusinessLogic(ByVal value As Integer)
‘ ここには純粋な数値ビジネスロジックのみを記述できる
‘ Nullチェックや型変換エラーの心配はゼロ
End Sub

End Class

4. 現場のプロが教える:ファイル・DB連携における実践知

実務の現場では、単一の文字列だけでなく、CSVファイルのインポートやデータベースのDataReaderからの値の取り出しなど、より実践的なシーンでこの知見が問われる。

① データベースからのDBNull対策

DBから取得した値(`DataRow(“ColumnName”)` など)は、データベース側で `NULL` が許容されている場合、VB.NET側では `DBNull.Value` として返ってくる。これをそのまま `TryParse` や `CInt` に突っ込むと型不一致エラーになる。

アンチパターン:

‘ DBNullの可能性があるのに直接キャストすると即死する
Dim val As Integer = CInt(row(“Quantity”))

堅牢な実装アプローチ:

Dim quantity As Integer = 0

‘ IsDBNull チェックと TryParse の組み合わせ
If row(“Quantity”) IsNot DBNull.Value Then
‘ ToString()を挟むことで、DBの数値型・文字列型を問わず安全にパース可能
Integer.TryParse(row(“Quantity”).ToString(), quantity)
End If

‘ あるいは、C#における和集合演算子的な拡張や、If演算子を活用する
Dim rawStr As String = If(row(“Quantity”) Is DBNull.Value, String.Empty, row(“Quantity”).ToString())
If Not Integer.TryParse(rawStr, quantity) Then
quantity = 0 ‘ 失敗時はデフォルト値
End If

② カンマや通貨記号が含まれるCSVの処理

外部システムから連携されるCSVファイルには、数値に `1,200` のようなカンマや `¥` マークが含まれていることが多々ある。
この場合、単なる `Integer.TryParse` では `False` になってしまうため、数値書式(NumberStyles)を指定するか、あらかじめ不要な文字を置換する必要がある。

Imports System.Globalization

Public Sub ParseComplexNumberString()
Dim rawInput As String = ” 1,230 円 ”
Dim cleanValue As Integer

‘ アプローチA: 文字列をクレンジングしてから TryParse
Dim sanitized = rawInput.Replace(“円”, “”).Replace(“,”, “”).Trim()

If Integer.TryParse(sanitized, cleanValue) Then
Console.WriteLine($”クレンジング後パース成功: {cleanValue}”) ‘ 1230
End If

‘ アプローチB: NumberStyles を指定してパースする(より高度)
‘ カンマや通貨記号、空白を許容するフラグを指定
Dim style As NumberStyles = NumberStyles.AllowIntegerNumber Or NumberStyles.AllowThousands Or NumberStyles.AllowCurrencySymbol

If Integer.TryParse(rawInput, style, CultureInfo.CurrentCulture, cleanValue) Then
Console.WriteLine($”スタイル指定パース成功: {cleanValue}”)
End If
End Sub

5. チーフアーキテクトからの総括

レガシーな `CInt`、`CLng`、そして曖昧な `Val` 関数は、VB.NETの歴史的遺産であり、現代の堅牢なアプリケーション開発においては「負債」でしかない。

  • 例外処理(Try-Catch)をパフォーマンスの要所に多用しないこと。
  • 不確定な外部入力(ユーザー、ファイル、DB)に対しては、必ず `TryParse` による事前検証(ガード・クラウス)を行うこと。

この2点をチーム全体のコーディング規準として徹底するだけで、アプリの安定性は劇的に向上し、「原因不明の強制終了」に怯える夜から解放されるはずだ。

あなたの書くコードの堅牢性が、ビジネスの信頼性を支えている。さあ、今すぐプロジェクト内のレガシー変換を洗い出し、モダンな `TryParse` へリプレースしよう。

タイトルとURLをコピーしました