例外処理乱用の落とし穴
例外処理(try-catch
)は、C#において非常に強力なエラーハンドリング手段です。しかし、その便利さゆえに「とりあえず囲っておこう」と安易に使ってしまうと、コードの品質やパフォーマンスに悪影響を及ぼすことがあります。
この記事では、例外処理の乱用による問題点と再スローの誤用による問題点、正しい使い方について解説します。
✅ 例外処理の基本
C#では、例外が発生する可能性のあるコードを try
ブロックで囲み、エラーが発生した場合に catch
ブロックで処理します。
try
{
int result = 10 / int.Parse("0");
}
catch (DivideByZeroException ex)
{
Console.WriteLine("0で割ることはできません: " + ex.Message);
}
⚠️ 例外処理の乱用
❌ よくある悪い例
try
{
if (File.Exists("data.txt"))
{
string content = File.ReadAllText("data.txt");
Console.WriteLine(content);
}
}
catch
{
// 何もしない
}
このコードの問題点:
- 例外を握りつぶしている(catch内が空)
- 事前にチェックできる処理に例外を使っている
- 何が起きたのかログも出さない
🧨 例外処理の乱用が招く問題
問題点 | 説明 |
---|---|
可読性の低下 | 何が起きているのか分かりにくくなる |
デバッグ困難 | エラーの原因が追跡できない |
パフォーマンス低下 | 例外処理はコストが高い |
設計の劣化 | 本来の制御フローが崩れる |
🔁 再スローの誤用
例外をキャッチした後、適切に再スローしないことも大きな問題です。
❌ 悪い例:throw ex;
を使う
catch (Exception ex)
{
Log(ex);
throw ex; // スタックトレースが失われる
}
この書き方では、元のスタックトレースが失われてしまい、デバッグが困難になります。
✅ 正しい再スローの方法:throw;
を使う
catch (Exception ex)
{
Log(ex);
throw; // スタックトレースを保持したまま再スロー
}
✅ 正しい例外処理の使い方
✔️ 予測できるエラーは事前にチェック
if (File.Exists("data.txt"))
{
string content = File.ReadAllText("data.txt");
Console.WriteLine(content);
}
else
{
Console.WriteLine("ファイルが存在しません。");
}
✔️ 例外は「本当に予期しない事態」に使う
try
{
string content = File.ReadAllText("data.txt");
Console.WriteLine(content);
}
catch (IOException ex)
{
Console.WriteLine("ファイルの読み込み中にエラーが発生しました: " + ex.Message);
}
ベストプラクティスまとめ
- 事前にチェックできることはチェックする
- catchは具体的な例外型で行う
- ログを残す
- 例外を握りつぶさない
- ループ内でのtry-catchは避ける
例外処理は「最後の砦」です。便利だからといって多用すると、かえってバグの温床になります。
「例外は例外的なときに使う」 この原則を忘れず、堅牢で読みやすくデバッグしやすいC#コードを目指しましょう。