みなさん、こんにちは!日々の業務自動化やシステム開発、お疲れ様です。
VBAの「マクロの記録」から一歩踏み出し、VB.NETでの本格的なデスクトップアプリやWebアプリの開発に挑戦している方も多いのではないでしょうか。VBAからステップアップしたとき、多くの人が最初に戸惑う、そして最も重要となるテーマが「例外処理(エラーハンドリング)」です。
VBAでは `On Error GoTo ErrorHandler` や `On Error Resume Next` といった命令を使っていましたよね。しかし、VB.NETをはじめとする現代の.NET言語では、より安全で構造化された`Try-Catch-Finally`という仕組みを使います。
「アプリが急に黙って落ちてしまう…」
「エラーが出ているけれど、原因がさっぱり分からない…」
そんな悩みも、正しい例外処理とログ出力をマスターすれば一発で解決できます。ここをクリアすれば、Visual Basic (VB / VB.NET)の基本はバッチリですよ!
今回は、初心者の方が絶対に押さえておくべき「Try-Catch-Finallyの正しい書き方」と「開発の現場で役立つログ出力の基本」を、優しく、そして本質からしっかり解説していきます。
—
1. 例外処理とは?なぜ Try-Catch-Finally が必要なのか
プログラムを動かしていると、予測できないトラブルが必ず発生します。
- 「開こうとしたファイルが存在しない」
- 「ネットワークが途中で切断された」
- 「ユーザーが数値入力欄に『あいうえお』と入力した」
これらをプログラミング用語で「例外(Exception)」と呼びます。
もし例外を放置しておくと、Windowsアプリは「問題が発生したため終了しました」という不吉な画面を出して突然終了(クラッシュ)してしまいます。業務で使っているツールが急に消えて作業データが吹き飛んだら、ユーザーは青ざめてしまいますよね。
これを防ぎ、「エラーが起きても安全にアプリを継続させる」あるいは「安全に終了させて何が起きたかログを残す」ために使うのが、`Try-Catch-Finally` ステートメントです。
—
2. Try-Catch-Finally の構造と役割(図解的イメージ)
構造はとてもシンプルです。アトラクションの「安全装置」をイメージしてみてください。
Try
‘ 【実行エリア】
‘ 本来やりたいメインの処理を書く
Catch ex As Exception
‘ 【トラブル対処エリア】
‘ エラーが発生したときだけ実行される処理(ログ出力やユーザーへの通知)
Finally
‘ 【後片付けエリア】
‘ エラーの有無にかかわらず、最後に「必ず」実行される処理
End Try
それぞれのアクションを詳しく見てみましょう。
① Try ブロック(挑戦する場所)
トラブルが起きそうな「本命の処理」を記述します。ここを実行中に何かエラーが起きると、即座に実行が中断され、下の `Catch` にジャンプします。
② Catch ブロック(受け止める場所)
エラーが発生した時だけ通り抜ける「防護ネット」です。発生したエラーの情報は `ex` という変数に格納されます(変数名は自由ですが、慣例的に `ex` をよく使います)。ここで「エラーログの書き出し」や「ユーザーへの優しいエラーメッセージ表示」を行います。
③ Finally ブロック(後片付けをする場所)
ここが非常に重要です!
処理が成功しようが、エラーが発生して `Catch` に飛び込もうが、「何がなんでも絶対に最後に実行される場所」です。
ファイルを開いた後の閉じる処理(`.Close()`)や、データベース接続の解除など、リソースの解放漏れ(メモリリーク)を防ぐために使用します。
—
3. 初心者が陥りやすい「3つの罠(アンチパターン)」
正しく使えば強力な `Try-Catch-Finally` ですが、書き方を間違えると「逆にバグの原因が全く分からなくなる」という恐ろしい事態に陥ります。よくある罠を覚えておきましょう。
罠①:エラーの握りつぶし(空のCatch)
‘ ❌ 絶対にやってはいけない書き方!
Try
Dim num As Integer = Integer.Parse(txtInput.Text)
Catch ex As Exception
‘ 何も書かない…
End Try
エラーが起きても無視して進むため、一見正常に動いているように見えます。しかし内部のデータは崩壊しており、後から原因不明の巨大なバグとなって襲いかかってきます。VBAの `On Error Resume Next` を乱用していた人がやりがちな罠です。
罠②:何でもかんでも `Exception` 1つで受けてしまう
エラーには「ファイルがない(`FileNotFoundException`)」「ゼロで割った(`DivideByZeroException`)」など、さまざまな種類があります。
すべてのエラーを大雑把に捕まえるのではなく、予測できるエラーは個別に捕まえるのがプロの作法です。
罠③:`Throw ex` でスタックトレースを消してしまう
キャッチしたエラーをさらに呼び出し元へ投げ直す(再スローする)とき、以下のように書いてはいけません。
‘ ❌ エラーの発生場所(行番号など)の履歴が消えてしまう
Catch ex As Exception
Throw ex
End Catch
‘ ⭕ 正しい書き方(履歴を保持したまま上に投げる)
Catch ex As Exception
Throw
End Catch
単に `Throw` とだけ書くことで、エラーが「どこで発生したのか」という貴重な足跡(スタックトレース)を壊さずに保持できます。
—
4. 現場で使える!実践コード例(ファイル読み込みとログ出力)
それでは、実際に動くコードを見てみましょう。
指定したテキストファイルを読み込み、万が一エラーが起きた場合はログファイルに詳細を書き出すプログラムです。コピペしてご自身の環境で試してみてください。
Imports System.IO
Module Module1
Sub Main()
‘ 読み込みたいファイルのパス
Dim filePath As String = “C:\Temp\SampleData.txt”
‘ ファイル読み込み処理を実行
Dim content As String = ReadTextFile(filePath)
Console.WriteLine(“— 処理終了 —“)
Console.ReadLine()
End Sub
”’
”’
”’ ファイルパス
”’
Public Function ReadTextFile(ByVal path As String) As String
‘ ファイルを閉じるためのストリーム変数を宣言
Dim reader As StreamReader = Nothing
Dim fileContent As String = String.Empty
Try
Console.WriteLine(“ファイルの読み込みを開始します…”)
‘ ファイルを開く(ファイルが存在しないとここで例外が発生!)
reader = New StreamReader(path, System.Text.Encoding.UTF8)
fileContent = reader.ReadToEnd()
Console.WriteLine(“ファイルの読み込みに成功しました。”)
‘ — 個別の例外処理(ピンポイントで捕捉) —
Catch ex As DirectoryNotFoundException
Console.WriteLine(“【エラー】指定されたフォルダが存在しません。”)
WriteErrorLog(“フォルダ不在エラー”, ex)
Catch ex As FileNotFoundException
Console.WriteLine(“【エラー】指定されたファイルが見つかりません。”)
WriteErrorLog(“ファイル不在エラー”, ex)
‘ — それ以外の想定外のエラーを一網打尽 —
Catch ex As Exception When Not TypeOf ex Is OperationCanceledException
‘ VB.NET特有の「When句」を使って、特定の条件だけでCatchすることも可能!
Console.WriteLine(“【予期せぬエラー】システムエラーが発生しました。”)
WriteErrorLog(“予期せぬシステムエラー”, ex)
Finally
‘ — 後片付け処理(エラーが起きても起きなくても必ず通る) —
If reader IsNot Nothing Then
reader.Close()
reader.Dispose()
Console.WriteLine(“ファイルリソースを正常に解放しました。”)
End If
End Finally
Return fileContent
End Function
”’
”’
Public Sub WriteErrorLog(ByVal title As String, ByVal ex As Exception)
Dim logDirPath As String = “C:\Temp\Logs”
Dim logFilePath As String = Path.Combine(logDirPath, “AppError.log”)
Try
‘ ログ保存用フォルダが存在しない場合は作成
If Not Directory.Exists(logDirPath) Then
Directory.CreateDirectory(logDirPath)
End If
‘ ログメッセージの組み立て(日時、タイトル、メッセージ、スタックトレース)
Dim logMessage As String = $”[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{title}]” & vbCrLf &
$”メッセージ: {ex.Message}” & vbCrLf &
$”発生場所 : {ex.StackTrace}” & vbCrLf &
New String(“-“c, 60) & vbCrLf
‘ 追記モード(Append)でログファイルに書き込み
File.AppendAllText(logFilePath, logMessage, System.Text.Encoding.UTF8)
Catch logEx As Exception
‘ ログ出力自体が失敗した場合はコンソールに出す(ログ出力のエラーでアプリを止めない工夫)
Console.WriteLine($”ログ書き込みに失敗しました: {logEx.Message}”)
End Try
End Sub
End Module
【プロの補足】リソース解放は `Using` を使うともっとスマート!
VB.NETには、`Finally` でファイル等を閉じる処理を自動化してくれる `Using` ステートメント という超便利な構文があります。
‘ Usingブロックを抜けると、エラーの有無に関わらず自動的に Dispose(解放)される!
Try
Using reader As New StreamReader(path, System.Text.Encoding.UTF8)
Return reader.ReadToEnd()
End Using
Catch ex As FileNotFoundException
WriteErrorLog(“ファイル不在”, ex)
Return String.Empty
End Try
実務では `Using` と `Try-Catch` を組み合わせて書くのがスタンダードですので、慣れてきたらぜひ使ってみてくださいね。
—
5. デバッグログに残すべき「3大情報」
エラーログを出力する際、最低限絶対に含めなければならない情報が3つあります。
1. 発生日時(`DateTime.Now`)
- 「いつ起きたのか」が分からないと、ログ調査が不可能です。
2. エラーメッセージ(`ex.Message`)
- 「何が起きたのか」を人が読める形式で教えてくれます。
3. スタックトレース(`ex.StackTrace`)
- 一番大事です! ソースコードの何行目でエラーが発生したのかという「犯行現場の足跡」が全て記録されています。
開発中はもちろん、お客様の環境にアプリを納品したあと「動かないんだけど!」と言われたとき、このログファイル送ってもらうだけで一発で原因が特定できるようになります。ログは「未来の自分を救うタイムマシン」なのです。
—
6. まとめ
お疲れ様でした!今回はVB.NETにおける例外処理の基本とログ出力について解説しました。
- `Try`: エラーが起きそうな処理に挑戦する
- `Catch`: 起きたエラーを捕まえて、ログを残す(`Throw ex` ではなく `Throw` を使う)
- `Finally`: リソースの後片付けを絶対に行う(または `Using` を使う)
- ログ: 「日時」「メッセージ」「スタックトレース」を必ずセットで残す
例外処理は、単にアプリを落ちないようにする「おまじない」ではありません。「ユーザーに嫌な思いをさせず、開発者が迅速に原因を特定するための思いやり」の技術です。
ここをマスターすれば、VBA脱却・VB.NET初心者からの脱出は目と鼻の先です。
ぜひご自身の書いているコードに `Try-Catch-Finally` を取り入れて、壊れにくく信頼性の高いプログラムを作成してみてくださいね!応援しています!
