Day 51 のゴールと全体像
Day 51 では、いよいよ 「例外処理」に踏み込みます。 キーワードはこの4つです。
trycatchfinallythrow
どれも C# ではおなじみの構文ですが、 「なんとなく使っている」状態から一歩進んで、 “なぜそう書くのか” を理解しながら使えるようになることを目指します。
例外処理は、アプリを「落ちないようにする」ための仕組みであり、 同時に「安全に失敗する」ための技術でもあります。 少しだけ緊張感のあるテーマですが、 肩の力を抜いて、雑誌を読むような気持ちで進めていきましょう。
例外とは何かをイメージする
「普通じゃない事態」が起きたときの合図
まずは「例外」という言葉のイメージから整理してみます。
プログラムを動かしていると、
- ファイルが見つからない
- ネットワークにつながらない
- 数値の計算で 0 で割ってしまった
- ユーザーが変な入力をした
など、「想定外」「異常系」の出来事が起こります。
こうした “普通の処理では扱えない事態” を、 C# では 例外(Exception) として表現します。
例外が発生すると、
- その場の処理は中断される
- 例外を「キャッチ」できる場所まで、処理がジャンプする
という流れになります。 この「ジャンプ」を、try / catch / finally / throw でコントロールしていくイメージです。
try と catch の基本構造
まずは形から覚える
例外処理の基本形は、次のような構文です。
try
{
// 例外が発生するかもしれない処理
}
catch (Exception ex)
{
// 例外が発生したときの処理
}
C#とてもシンプルですが、 この2つが例外処理の「心臓部」です。
具体例:0 で割ってしまうケース
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("割り算をします。分子を入力してください。");
string numeratorText = Console.ReadLine();
Console.WriteLine("分母を入力してください。");
string denominatorText = Console.ReadLine();
try
{
// 文字列を整数に変換
int numerator = int.Parse(numeratorText);
int denominator = int.Parse(denominatorText);
// ここで 0 で割ると例外が発生する可能性がある
int result = numerator / denominator;
Console.WriteLine($"結果: {result}");
}
catch (FormatException ex)
{
// 数字に変換できなかった場合
Console.WriteLine("数字として解釈できない入力がありました。もう一度入力してください。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (DivideByZeroException ex)
{
// 0 で割ろうとした場合
Console.WriteLine("分母に 0 は指定できません。別の値を入力してください。");
Console.WriteLine($"詳細: {ex.Message}");
}
Console.WriteLine("処理が終了しました。");
Console.ReadLine();
}
}
C#ここで押さえておきたいポイント:
tryブロックには「例外が起きるかもしれない処理」をまとめて書きます。catchブロックには「例外が起きたときにどう振る舞うか」を書きます。catchは複数書くことができ、 例外の種類ごとに違う対応をすることが可能です。
ユーザーの入力が多少おかしくても、 プログラム全体が「落ちて終わり」にならず、 “ちゃんと怒って、ちゃんと生き残る” ようになるわけですね。
finally の役割
「例外が起きても起きなくても、最後に必ずやること」
try / catch に続いて登場するのが finally です。
構文はこうなります。
try
{
// 例外が発生するかもしれない処理
}
catch (Exception ex)
{
// 例外が発生したときの処理
}
finally
{
// 例外の有無にかかわらず、最後に必ず実行される処理
}
C#finally は、
- ファイルを閉じる
- 接続を切る
- 一時的なリソースを解放する
といった 「後片付け」 を書く場所として使われます。
具体例:ファイルを開いて読むとき
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
StreamReader reader = null;
try
{
// ファイルを開く(存在しないと例外が発生する)
reader = new StreamReader("data.txt");
string content = reader.ReadToEnd();
Console.WriteLine("ファイルの内容:");
Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
Console.WriteLine("ファイルが見つかりませんでした。ファイル名を確認してください。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (IOException ex)
{
Console.WriteLine("ファイルの読み込み中にエラーが発生しました。");
Console.WriteLine($"詳細: {ex.Message}");
}
finally
{
// ここは例外が起きても起きなくても必ず実行される
if (reader != null)
{
reader.Dispose(); // ファイルを閉じる
Console.WriteLine("ファイルを閉じました。");
}
}
Console.WriteLine("プログラムを終了します。");
Console.ReadLine();
}
}
C#重要なポイント:
finallyは「必ず実行される」ことが保証されているブロックです。- 例外が発生しても、
catchの後にfinallyが呼ばれます。 - 後片付けやリソース解放をここに書いておくと、 「例外が起きたせいでファイルが開きっぱなし」などの事故を防ぎやすくなります。
throw の意味と使いどころ
「自分から例外を投げる」という行為
ここまでの例では、 例外は「勝手に発生するもの」として扱ってきました。
しかし、実務では
「この状況はおかしいから、 ここで明示的に例外を投げておきたい」
という場面がよくあります。
そんなときに使うのが throw です。
具体例:引数チェックで throw する
using System;
class Calculator
{
// 分母が 0 のときは例外を投げるメソッド
public int Divide(int numerator, int denominator)
{
if (denominator == 0)
{
// 自分で例外を投げる
throw new ArgumentException("分母に 0 は指定できません。", nameof(denominator));
}
return numerator / denominator;
}
}
class Program
{
static void Main(string[] args)
{
var calc = new Calculator();
try
{
int result = calc.Divide(10, 0);
Console.WriteLine($"結果: {result}");
}
catch (ArgumentException ex)
{
Console.WriteLine("不正な引数が渡されました。");
Console.WriteLine($"パラメータ名: {ex.ParamName}");
Console.WriteLine($"メッセージ : {ex.Message}");
}
Console.ReadLine();
}
}
C#ここでのポイント:
throwは「例外を発生させる」ためのキーワードです。new ArgumentException(...)のように、 例外オブジェクトを作って投げることで、 「何がおかしいのか」を呼び出し側に伝えることができます。
「握りつぶさない」ための throw
もうひとつ大事な使い方として、
catch で一度例外を受け取りつつ、 ログを残してから、再度
throwする
というパターンがあります。
try
{
// 何かの処理
}
catch (Exception ex)
{
// ログを残す
Console.WriteLine($"エラー発生: {ex.Message}");
// もう一度投げて、上位の層に判断を委ねる
throw;
}
C#このように、
- 「ここでは対処しきれない」
- 「もっと上の層で判断してほしい」
というときに、 例外を握りつぶさずに再度投げることで、 システム全体としての安全性を保ちやすくなります。
例外処理の基本テンプレート
よく使う形をひとつ覚えておく
最後に、初心者向けの「基本テンプレート」をまとめておきます。
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
StreamReader reader = null;
try
{
Console.WriteLine("読み込むファイル名を入力してください。");
string fileName = Console.ReadLine();
// 例外が発生するかもしれない処理
reader = new StreamReader(fileName);
string content = reader.ReadToEnd();
Console.WriteLine("ファイルの内容:");
Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
// 特定の例外に対する処理
Console.WriteLine("指定されたファイルが見つかりませんでした。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (IOException ex)
{
// 入出力全般の例外に対する処理
Console.WriteLine("ファイルの読み込み中にエラーが発生しました。");
Console.WriteLine($"詳細: {ex.Message}");
}
catch (Exception ex)
{
// 想定していない例外の最後の受け皿
Console.WriteLine("予期しないエラーが発生しました。");
Console.WriteLine($"詳細: {ex.Message}");
}
finally
{
// 後片付け(例外の有無にかかわらず実行される)
if (reader != null)
{
reader.Dispose();
Console.WriteLine("ファイルを閉じました。");
}
}
Console.WriteLine("プログラムを終了します。");
Console.ReadLine();
}
}
C#このテンプレートには、
try:例外が起きるかもしれない処理catch:例外ごとの対処catch (Exception ex):最後の受け皿finally:後片付け
という、例外処理の基本要素がすべて詰まっています。
Day 51 のまとめ
Day 51 では、
- 例外とは何か → 「普通じゃない事態」を表す仕組み
try/catch→ 例外が起きるかもしれない処理と、その対処を分けて書く構文finally→ 例外の有無にかかわらず、最後に必ず実行したい処理を書く場所throw→ 自分で例外を発生させたり、 一度受け取った例外を再度投げたりするためのキーワード
を、具体的なコード例とともに学びました。
例外処理は、 「バグを隠すためのもの」ではなく、 「失敗をきちんと扱うための技術」です。
ぜひ、
- 自分で小さなサンプルを書いて、わざと例外を起こしてみる
catchの中でメッセージを変えてみるfinallyにログ出力を追加してみる
といった小さな実験を通して、 例外処理を「怖いもの」ではなく、 頼れる相棒のような存在として、 少しずつ手になじませていってください。

