アプリケーション開発において、予期せぬエラー(例外)への対策は不可欠です。外部ファイルの読み込み失敗、ネットワークの切断、あるいは不正な計算など、実行時に発生する問題に対して適切に処置を行わない場合、アプリケーションは強制終了してしまいます。
C#ではtry-catch-finally構文を使用することで、これらの例外を捕捉し、適切なエラーハンドリングやリソースの解放を行うことができます。ここでは、タスク進捗率の計算処理を題材に、基本的な例外処理の実装方法について解説します。
try-catch-finallyの基本構造
例外処理の基本構成は以下の3つのブロックから成り立ちます。
- try: 例外が発生する可能性があるコードを記述します。
- catch: 発生した例外を捕捉し、エラーメッセージの表示やリカバリ処理を行います。
- finally: 例外の有無にかかわらず、必ず実行したい処理(リソースの解放など)を記述します。
実践的なコード例:進捗率計算時のゼロ除算対策
以下のコードは、プロジェクトのタスク消化数から進捗率を計算する処理です。「全タスク数」が0の場合(プロジェクト開始前など)に発生するゼロ除算エラーを適切にハンドリングする例です。
using System;
namespace ProjectManagement
{
class Program
{
static void Main()
{
// シナリオ:
// プロジェクトの進捗率を計算したい。
// しかし、データ不備により「全タスク数」が 0 になっている可能性がある。
int totalTasks = 0; // 全タスク数(本来は1以上であるべき)
int completedTasks = 5; // 完了タスク数
try
{
// ここで例外が発生する可能性があります。
// 整数同士の割り算で分母が0の場合、DivideByZeroException がスローされます。
Console.WriteLine("計算を開始します...");
int progressRate = (completedTasks * 100) / totalTasks;
Console.WriteLine($"進捗率: {progressRate}%");
}
catch (DivideByZeroException ex)
{
// ゼロ除算が発生した場合の特定の処理
Console.Error.WriteLine("エラー: タスク数が0のため進捗率を計算できません。");
// ログ出力などの処理をここに記述します
// Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
// その他の予期せぬ例外すべてを捕捉する汎用的な処理
Console.Error.WriteLine($"予期せぬエラーが発生しました: {ex.Message}");
}
finally
{
// 例外の有無にかかわらず必ず実行されるブロック
// データベース接続の切断やファイルハンドルの解放などをここで行います。
Console.WriteLine("計算処理を終了します。");
}
}
}
}
実行結果
計算を開始します...
エラー: タスク数が0のため進捗率を計算できません。
計算処理を終了します。
技術的なポイントと注意点
1. 捕捉する例外の順序
catchブロックは上から順に評価されます。そのため、より具体的(派生クラス)な例外を先に記述し、汎用的なExceptionクラスは最後に記述する必要があります。もしExceptionを先に書いてしまうと、すべての例外がそこで捕捉されてしまい、特定の例外(DivideByZeroExceptionなど)に対する個別の処理が実行されなくなります。
2. 整数と浮動小数点の挙動の違い
C#において、ゼロ除算で例外が発生するのは整数型(int, longなど)の場合のみです。 浮動小数点型(double, float)でゼロ除算を行った場合、例外は発生せず、結果はInfinity(無限大)またはNaN(非数)となります。
// double型の場合
double total = 0.0;
double current = 10.0;
double result = current / total; // 例外は発生せず、Infinity になる
3. 例外を握りつぶさない
catchブロック内を空にすること(通称:例外の握りつぶし)は避けるべきです。エラーが発生した事実が隠蔽され、バグの原因究明が極めて困難になります。最低限、ログへの出力を行うか、処理の継続が不可能な場合は例外を再スロー(throw;)する設計が求められます。
まとめ
try-catch-finallyを適切に使用することで、予期せぬエラーが発生してもアプリケーションをクラッシュさせることなく、ユーザーに適切なフィードバックを返すことができます。「正常系」のコードだけでなく、「異常系」の考慮を行うことは、プロフェッショナルな品質を担保する上で必須の要件です。
