VB.NET数値変換の罠:CInt・CLng・Valを捨て、TryParseで堅牢な業務システムを構築する方法
開発現場でよく見かける光景がある。画面のテキストボックスやCSVから読み込んだ文字列を、安易に `CInt` や `Val` で数値化し、ユーザーが全角スペースや想定外の文字を入力した瞬間に容赦なくクラッシュする業務アプリケーション。あるいは、何百万件ものログ集計中に突如発生する「オーバーフローしました」という例外。
笑い事ではない。こうしたレガシーな数値変換の無知は、そのままシステムの信頼性低下、ひいては業務停止に直結する。
私はこれまで数多くのデスクトップ業務自動化ツールや基幹連携システムのコードレビューを行ってきたが、「数値変換の甘さ」に起因するバグは、実に全体の3割を占める。
今回は、VB.NETにおける数値変換のダークサイド(`Val`, `CInt`, `CLng`)を解剖し、現代の.NET開発においてなぜ `TryParse` 一択なのか、その理由と実践的な実装パターンをチーフアーキテクトの視点から伝授する。
—
1. レガシーな数値変換関数がはらむ「3つの致命的欠陥」
まずは、VB6の時代から引き継がれてきた古い関数たちが、なぜモダンな業務システムにおいて「地雷」となるのかを整理しておこう。
① `Val` 関数:バグの温床となる「テキトーリーディング」
`Val` 関数は文字列の先頭から数値を読み取り、数値とみなせない文字が現れた時点でそこまでの値を返すという、極めて「おせっかい」な仕様を持つ。
- `Val(“12345円”)` ➔ `12345` (一見動くように見えるが……)
- `Val(“12,345”)` ➔ `12` (「,」を区切り文字と認識せず、そこでパースを止める!)
- `Val(“A123”)` ➔ `0` (エラーを出さずに勝手に `0` に化ける)
業務システムにおいて、「入力ミスした金額が、エラーにもならず勝手に切り捨てられたりゼロになったりする」ことは、データ破損と同義である。サイレント・フェイル(沈黙する障害)ほど恐ろしいものはない。
② `CInt` / `CLng` 関数:容赦なき例外クラッシュ
`CInt` や `CLng` は、.NETの型キャスト(`Convert.ToInt32`等)のラッパーである。これらは安全側に倒れている(不正な文字列なら例外を投げる)が、「例外による制御フロー」はパフォーマンスとコードの可読性を著しく落とす。
さらに、2,147,483,647(Integerの限界)を超える文字列を `CInt` に放り込むと、容赦なく `System.OverflowException` が発生し、アプリケーションが強制終了する。
③ 暗黙の型変換(Option Strict Off の呪縛)
プロジェクトの設定で `Option Strict Off`(または無指定)にしている現場は今すぐ改めるべきだ。これがあると、文字列と数値の演算が暗黙裏に行われ、意図しない型変換やパフォーマンス低下(ボックス化・アンボックス化)を引き起こす。
—
2. 救世主:`Int32.TryParse` (または `Int64.TryParse`)
モダンな.NET開発における数値変換の黄金律は、「例外を発生させずに、成否をBooleanで返す」 `TryParse` パターンの採用である。
`TryParse` の圧倒的な優位性
1. 安全な制御: 例外オブジェクトを生成・スローしないため、パフォーマンスが高い。
2. 明確な成否判定: 変換できたかどうかを `Boolean` で返すため、if文によるバリデーションと直結する。
3. 厳密なパース: 余計な文字が混ざっていれば、問答無用で「変換失敗」と判定する(業務アプリではこれが正しい)。
—
3. 【実践】プロダクションコード:堅牢な入力値検証と数値変換
それでは、実際の業務アプリケーション(Windows FormsやWPF、あるいはバッチ処理)でそのまま使える、堅牢なヘルパーメソッドを含む実装例を提示する。
Imports System
Namespace BusinessAutomation.Utilities
Public Module NumberConverter
”’
”’ 失敗時は指定されたデフォルト値を返します。
”’
”’ 変換対象の文字列
”’ 変換失敗時のデフォルト値(既定値: 0)
”’
Public Function SafeToInt32(input As String, Optional defaultValue As Integer = 0) As Integer
‘ Nullまたは空白文字のチェック
If String.IsNullOrWhiteSpace(input) Then
Return defaultValue
End If
‘ 前後の空白や、全角数字・全角カンマなどのノイズを考慮する場合、
‘ ここで事前にTrimや半角変換を行うのがプロの技。
Dim sanitizedInput As String = input.Trim()
Dim result As Integer
‘ TryParseの鉄則:パース成功時はout変数(VBではByRef)に格納されTrueを返す
If Integer.TryParse(sanitizedInput, result) Then
Return result
Else
‘ ログ出力基盤があれば、ここで不正値の警告ログを記録する
‘ Logger.Warn($”数値変換に失敗しました: ‘{input}’ をデフォルト値 ‘{defaultValue}’ にフォールバックします。”)
Return defaultValue
End If
End Function
”’
”’
Public Function SafeToInt64(input As String, Optional defaultValue As Long = 0) As Long
If String.IsNullOrWhiteSpace(input) Then Return defaultValue
Dim result As Long
If Int64.TryParse(input.Trim(), result) Then
Return result
End If
Return defaultValue
End Function
End Module
End Namespace
画面入力やファイル連携での実際の使い方
‘ — 実際のフォームやバッチ処理での利用例 —
‘ 画面のテキストボックスから取得した値(例: ” 12345 ” や “ABC”)
Dim rawInput As String = txtQuantity.Text
‘ 安全な変換の呼び出し
Dim quantity As Integer = NumberConverter.SafeToInt32(rawInput, 0)
If quantity = 0 AndAlso rawInput.Trim() <> “0” Then
‘ 変換に失敗し、かつユーザーが「0」以外を入力していた場合のバリデーション処理
MessageBox.Show(“数量には正しい数値を入力してください。”, “入力エラー”, MessageBoxButtons.OK, MessageBoxIcon.Warning)
txtQuantity.Focus()
Exit Sub
End If
‘ 以降、安全にビジネスロジックへ進む
—
4. ファイル・データベース連携における「型と桁あふれ」の防衛策
CSVファイルやExcel、外部API、SQLデータベースと連携する際、数値変換はさらにシビアになる。
① データベースの型との一致
SQL Serverの `INT` 型(上限約21億)に対し、VB側のデータ型を `Integer` (Int32) にしている場合、`CInt` を使っていると、万が一21億を超えるデータが飛んできた瞬間にシステムが停止する。
対策: データベース側のスキーマ変更が困難な場合は、必ず `Int64.TryParse` で受け取り、アプリケーション側で範囲チェック(`If val > Integer.MaxValue`)を行ってから `Integer` 型の変数に代入すること。
② Excel・CSVの「数値に見える文字列」の罠
CSVやExcelから読み込んだデータには、目に見えない制御文字(BOMやタブ、改行コード)が混入していることが多い。
`Integer.TryParse` に渡す前に、必ず以下のようなサニタイジング(無害化)挟むのが、トラブルを防ぐエンジニアの流儀である。
‘ 改行やタブ、不可視文字を除去する例
Dim cleanText As String = System.Text.RegularExpressions.Regex.Replace(rawData, “[\r\n\t]”, “”)
—
5. チーフアーキテクトからの提言
コードの品質は、こうした「細部へのこだわり」の積み重ねによって決まる。
「動けばいいや」と `Val()` や `CInt()` を安易に使うコードは、いつか必ず爆発する「技術的負債」の爆弾を抱えているようなものだ。
今すぐプロジェクト全体のコードを見直し、レガシーな数値変換関数を駆逐せよ。そして、`TryParse` をベースとした堅牢な入力値検証レイヤーを構築してほしい。それこそが、止まらない・壊れないプロフェッショナルな業務システムを創り上げる唯一の道である。
