こんにちは!開発現場の第一線で戦う皆さん、日々のコーディングお疲れ様です。
今回は、VB.NETでの「カスタム例外(独自の例外クラス)」の設計と実装について、一歩踏み込んで解説します。
「エラー処理って、とりあえず `Try…Catch` で囲んで `Exception` をキャッチしておけばいいんでしょ?」
もしあなたがそう思っているなら、ここから先の話は目からウロコかもしれません。
現場でよくある「残高不足」「入力値の重複」「ステータス不正」といった業務上のエラーと、データベース接続断やメモリ不足といったシステムの致命的エラーを一緒くたにしていないですか?これらを綺麗に分離し、上位レイヤーでスマートにハンドリングするための「プロの例外設計」を、優しく、かつ徹底的に伝授します。
ここをクリアすれば、あなたの書くコードの品質はワンランクもツーランクも跳ね上がりますよ。さあ、一緒に極意をマスターしましょう!
—
1. なぜ「業務エラー」と「システムエラー」を分けるべきなのか?
初学者や中級者にありがちなのが、すべてのエラーを `Exception` クラスのままスローし、catch 側でも `Catch ex As Exception` で一網打尽にしてしまうパターンのコードです。
.net
‘ ❌ やってはいけないアンチパターン
Try
‘ 銀行口座からの引き出し処理
AccountManager.Withdraw(accountId, 10000)
Catch ex As Exception
‘ すべてのエラーを同じメッセージで処理してしまう
MessageBox.Show(“エラーが発生しました: ” & ex.Message)
End Try
これの何が問題か分かりますか?
ユーザーが「残高が足りない(業務エラー)」という理由で失敗したのか、それとも「データベースが吹っ飛んだ(システムエラー)」という絶望的な状況なのかを、呼び出し側が判別できないのです。
業務エラーの場合は「もう一度金額を入力し直してください」と優しく促すべきですが、システムエラーの場合は「システム管理者に連絡してください」と表示し、ログに詳細を残さなければなりません。
ここで登場するのが、今回解説するカスタム例外です。
—
2. 実務で使える「業務エラーコード付き」カスタム例外の設計
それでは、VB.NETで独自の例外クラスを定義してみましょう。
実務では、単にメッセージ文字列を持つだけでなく、「エラーコード(識別子)」や「追加情報」を持たせることが極意となります。
以下のコードを見てください。これが現場で使えるプロのカスタム例外クラスのテンプレートです。
.net
Imports System
‘ =====================================================================
‘ 業務ロジック専用のベース例外クラス
‘ =====================================================================
Public Class BusinessLogicException
Inherits Exception
‘ 1. 業務固有のエラーコード(例: “ERR_INSUFFICIENT_FUNDS”)
Public Property ErrorCode As String
‘ コンストラクタ1: メッセージのみ
Public Sub New(message As String)
MyBase.New(message)
Me.ErrorCode = “ERR_UNKNOWN”
End Sub
‘ コンストラクタ2: メッセージとエラーコード
Public Sub New(message As String, errorCode As String)
MyBase.New(message)
Me.ErrorCode = errorCode
End Sub
‘ コンストラクタ3: メッセージ、エラーコード、内部例外(チェイン用)
Public Sub New(message As String, errorCode As String, innerException As Exception)
MyBase.New(message, innerException)
Me.ErrorCode = errorCode
End Sub
End Class
‘ =====================================================================
‘ さらに特化したカスタム例外(例:残高不足例外)
‘ =====================================================================
Public Class InsufficientFundsException
Inherits BusinessLogicException
‘ 追加情報:不足している金額
Public Property ShortageAmount As Decimal
Public Sub New(message As String, shortageAmount As Decimal)
‘ 基底クラスにメッセージと専用のエラーコードを渡す
MyBase.New(message, “ERR_INSUFFICIENT_FUNDS”)
Me.ShortageAmount = shortageAmount
End Sub
End Class
💡 コードのポイント解説
1. `Inherits Exception`: すべての例外の祖先である `Exception` クラスを継承します。これにより、VB.NETの標準的な例外機構(Throw / Catch)にそのまま乗せることができます。
2. `
3. エラーコードと追加プロパティ: `ErrorCode` や `ShortageAmount` を持たせることで、Catchした側で「なぜエラーになったのか」「あといくら必要なのか」をプログラム的に正確に判定できます。
—
3. 実際にカスタム例外を「スロー(Throw)」して「キャッチ」する
定義したカスタム例外を、実際の業務ロジックの中でどのように使うのかを見てみましょう。
.net
Public Class BankAccount
Private _balance As Decimal = 5000 ‘ 現在の口座残高(例として5,000円)
‘ 引き出しメソッド
Public Sub Withdraw(amount As Decimal)
If amount <= 0 Then
' 不正な金額指定は通常のArgumentExceptionなど
Throw New ArgumentException("引き出し金額は0より大きい値を指定してください。", NameOf(amount))
End If
If _balance < amount Then
' 残高不足は、先ほど作ったカスタム例外をスローする!
Dim shortage As Decimal = amount - _balance
Throw New InsufficientFundsException("口座残高が不足しています。", shortage)
End If
' 引き出し処理
_balance -= amount
Console.WriteLine($"{amount}円引き出しました。残高: {_balance}円")
End Sub
End Class
呼び出し側(UI層やコントローラー層)のスマートな実装
呼び出し側では、例外の型(Type)やエラーコードによって処理を美しく分岐させます。
.net
Public Sub OnWithdrawButtonClick()
Dim account As New BankAccount()
Try
‘ あえて残高を超える金額を引き出してみる
account.Withdraw(10000)
Catch ex As InsufficientFundsException
‘ 🎯 1. 業務エラー(残高不足)の専用ハンドリング
MessageBox.Show(
$”{ex.Message}” & vbCrLf &
$”エラーコード: {ex.ErrorCode}” & vbCrLf &
$”あと {ex.ShortageAmount.ToString(“N0″)} 円足りません。”,
“残高不足”, MessageBoxButtons.OK, MessageBoxIcon.Warning
)
‘ -> ユーザーに残高チャージ画面を案内するなどのリカバリへ誘導
Catch ex As BusinessLogicException
‘ 🎯 2. その他の業務エラーの汎用ハンドリング
MessageBox.Show($”業務エラーが発生しました: {ex.Message}”, “確認”, MessageBoxButtons.OK, MessageBoxIcon.Information)
Catch ex As Exception
‘ 🎯 3. 予期せぬシステムエラーのハンドリング
MessageBox.Show($”システムエラーが発生しました。管理者に連絡してください。” & vbCrLf & ex.Message, “エラー”, MessageBoxButtons.OK, MessageBoxIcon.Error)
‘ -> ログ出力処理へ流す
End Try
End Sub
—
4. 現場で陥りがちな罠とアンチパターン
ここで、実務でやりがちな「惜しい実装」についても触れておきます。
- アンチパターンA: 例外を握りつぶす
.net
Try
account.Withdraw(10000)
Catch ex As Exception
‘ 何もしない(または Console.WriteLine だけ)
End Try
エラーが起きているのに画面が平然とし続けている……これはユーザーにとってもデバッガーにとっても最悪の仕様です。例外は必ず「適切な層でキャッチしてユーザーに伝えるか、さらに上位へ再スロー(`Throw`)」しましょう。
- アンチパターンB: すべてをカスタム例外にする
「引数がNullだった」「配列のインデックスが範囲外だった」といったプログラミング上のミスは、.NET標準の `ArgumentNullException` や `ArgumentOutOfRangeException` を使うべきです。カスタム例外はあくまで「業務ルール違反(ビジネスロジック上の例外)」を表現するために取っておきましょう。
—
まとめ
いかがでしたでしょうか?
今回は、VB.NETにおけるカスタム例外の設計と実装の極意について解説しました。
- 業務エラーとシステムエラーを明確に分離する
- カスタム例外には `Exception` を継承させ、エラーコードや固有のプロパティを持たせる
- 呼び出し側では、例外の型ごとに適切なハンドリング(リカバリ)を行う
この設計手法を取り入れるだけで、コードの保守性は劇的に向上し、「プロっぽい、堅牢なシステム」が作れるようになります。
ここをクリアすれば、あなたのVB.NETのスキルは間違いなく中級者から上級者の領域へステップアップしていますよ。ぜひ、日々の開発現場のコードに取り入れてみてください!
