【テクニカル・上級編】初心者向け:VB.NETの例外処理(Try-Catch-Finally)の正しい書き方と、エラー発生時にアプリケーションをクラッシュさせないためのログ出力の基本 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

破滅を回避するエンジニアリング:VB.NET例外処理の「深淵」と「真実」

VBAの泥沼からVB.NETへと渡り歩き、数多のレガシーシステムを延命・刷新してきた諸君に告ぐ。
「とりあえず `Try-Catch` で囲めば落ちない」という甘い幻想は今すぐ捨てろ。不適切な例外処理は、アプリケーションをクラッシュさせるよりもタチの悪い「死んだゾンビプロセス」を量産する。

今回は、業務アプリケーションを堅牢に保ち、保守運用時に「何が起きたのか」を一撃で特定するための、極限の例外処理アーキテクチャを伝授する。

1. 「握りつぶし」は最大の罪悪である

初心者がやりがちな最悪のコードがこれだ。

‘ 悪い例:絶対にやってはいけない
Try
‘ 処理内容
Catch ex As Exception
‘ 何もしない、あるいはMsgBoxを出すだけ
End Try

例外を握りつぶすことは、「システムに目隠しをして時速100kmで荒野を走らせる」のと同じだ。なぜエラーが起きたのか、メモリの状態はどうだったのか、その痕跡を消し去ることは技術者としての冒涜である。

正しい例外処理の哲学

1. 回復不能なエラーは握りつぶさない。
2. ログは「呼び出しスタック」と共に記録せよ。
3. リソースは必ず解放せよ。

2. 実践的:Try-Catch-Finally の真の構造

単なる構文の解説はしない。現場で生き残るための「鉄板テンプレート」を提示する。

Public Sub ExecuteBusinessLogic()
Dim connection As IDisposable = Nothing ‘ リソース管理の徹底

Try
‘ ここにビジネスロジックを記述
‘ 例:Windows API呼び出しやDBコネクションのオープン

Catch ex As System.Data.SqlClient.SqlException
‘ 特定の例外をキャッチ(DB接続エラー等)
Logger.Write(“DB Error: ” & ex.Message, TraceLevel.Error)
Throw ‘ 必要に応じて再スローし、上位層でハンドリングさせる

Catch ex As Exception
‘ 予期せぬ致命的なエラーのログ出力
‘ スタックトレースを含めることが、調査の最短距離となる
Logger.Write(“Critical System Failure: ” & ex.ToString(), TraceLevel.Error)
Throw New ApplicationException(“業務処理中に致命的なエラーが発生しました。”, ex)

Finally
‘ 【重要】何があってもリソースを解放する
‘ オブジェクトがNothingでないことを確認してからDispose
If connection IsNot Nothing Then
connection.Dispose()
End If
End Try
End Sub

なぜ `ex.ToString()` なのか?

`ex.Message` だけでは不十分だ。`ex.ToString()` を呼び出すことで、例外の型、メッセージ、そして「どのメソッドの何行目で発生したか」を示すスタックトレースがすべて出力される。これがない障害調査は、暗闇での針探しに等しい。

3. レガシー・Windows API呼び出し時の「危うい境界」

VB.NETから `P/Invoke` でWindows APIを叩く際、例外処理の境界はさらに繊細になる。アンマネージド領域でエラーが起きると、CLR(共通言語ランタイム)が例外を捕捉できずにプロセスごと落ちることがある。

  • API呼び出しの直後に `Marshal.GetLastWin32Error` を確認せよ。
  • 構造体のマーシャリングミスは例外ではなく「メモリ破損」を引き起こす。

API連携を行う際は、必ず「ラッパーメソッド」を作成し、その内部でガードを固めろ。呼び出し側に直接APIを露出させるのは、セキュリティと安定性の両面で悪手だ。

4. メモリ最適化とオブジェクトのライフサイクル

VB.NETにおいて「GC(ガベージコレクタ)に任せれば良い」というのは、メモリを大量に消費するデスクトップアプリや常駐タスクでは怠慢だ。

  • `Using` ステートメントの徹底:

`IDisposable` を実装したクラス(Stream, DB Connection, Graphics等)は、必ず `Using` ブロック内で定義せよ。これは `Try-Finally` の糖衣構文であり、最も安全なリソース解放手法だ。

‘ Usingを使うことで、FinallyのDisposeを保証する
Using reader As New StreamReader(“data.txt”)
‘ 処理…
End Using ‘ ここで自動的にDisposeが呼ばれる

5. 伝説のアーキテクトからの提言

システムは「動くこと」がゴールではない。「止まった時に、誰でも即座に原因が分かり、安全に復旧できること」が真のゴールだ。

  • ログ出力には、外部ライブラリ(NLogやlog4net)を使え。 自作のログクラスでファイル排他制御にハマる時間は、エンジニアの寿命を削るだけだ。
  • 例外を「制御フロー」に使うな。 If文で解決できる条件分岐に例外を投げるのは、パフォーマンスの観点から極めて非効率である。

諸君、コードを書くときは常に「この処理が深夜3時の障害対応で呼び出された自分を助けてくれるか?」と自問自答せよ。その視点があれば、自ずと堅牢なコードが見えてくるはずだ。

次は、非同期処理における例外の伝播と、マルチスレッド環境での排他制御について深掘りしよう。現場からは以上だ。

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