Skip to content

第15章 例外処理

この章では、プログラムの実行中に発生するエラーに対応するための 例外処理(exception handling)を学習します。

これまでに何度も書いてきた次のコードを思い出してください。

string input = Console.ReadLine();
int number = int.Parse(input);

正しく数値が入力されれば問題なく動きますが、abc のような文字列が入力されると 実行中にエラー になります。 ファイル操作や DB 接続でも、同じように「実行してみないと分からない問題」がよく起こります。

入力ミス(数値以外、空文字)
ファイルが存在しない・アクセスできない
DB に接続できない・SQL が間違っている
ネットワークが切れている

このような実行時の問題に プログラムを落とさず安全に対応 する仕組みが、例外処理です。 特に、第 17 章以降の DB 接続では、例外処理が 必須 になります。

この章では次のことを目指します。

例外とは何かを知る
try-catch の基本形を使える
例外が発生してもプログラムを終了させずに対応できる
例外の種類を見分けられる
finally の役割を理解する
入力エラー・ファイル操作エラーに対応できる

この章でできるようになること

Section titled “この章でできるようになること”

この章を終えると、次のことができるようになります。

  • 例外とは何かを説明できる
  • 実行時エラーとコンパイルエラーの違いをおおまかに説明できる
  • try-catch の基本形を書ける
  • FormatException などの代表的な例外クラスを知っている
  • Exception オブジェクトからエラーメッセージを取得できる
  • 複数の catch を使って例外の種類ごとに処理を分けられる
  • catch の順序ルール(具体的な例外を先に)を説明できる
  • finally の役割を説明できる
  • int.TryParse で安全に数値入力を処理できる
  • throw で自分で例外を発生させられる
  • ファイル操作・DB 接続で例外処理が重要になる理由を説明できる

項目内容
開発環境Visual Studio 2022
プロジェクト種類コンソール アプリ
対象フレームワーク.NET 8
ソリューション名Chapter15
プロジェクト名Ch15_ExceptionHandling

csproj の Nullable は disable に変更してください

プロジェクト作成後、Ch15_ExceptionHandling.csproj を開き、<Nullable>disable</Nullable> に変更してください。

詳しい手順は、第 1 章「1-1 プロジェクトを作成する」を参照してください。


作業を始める前に、次の内容を確認してください。

  • Console.ReadLine で入力を受け取れる
  • int.Parse で文字列を数値に変換できる
  • if 文・while 文を書ける
  • メソッドを作成できる
  • ファイルの読み書き(File クラス)の基本(第 9 章)
  • 直前の章までの内容を Git に提出済みである

コンパイルエラーと実行時エラー

Section titled “コンパイルエラーと実行時エラー”

プログラムのエラーには大きく 2 種類あります。

種類発生タイミング
コンパイルエラー実行する前(VS の編集中に発見)セミコロン抜け、スペルミス、型不一致
実行時エラー(例外)実行中数値変換失敗、ファイル不存在、0 除算

コンパイルエラーは VS が赤波線で教えてくれるので比較的気付けます。 例外は実行してみないと分からない ため、対応を準備しておく必要があります。


次のコードを Program.cs に貼って実行してください。

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
Console.Write("整数を入力してください:");
string input = Console.ReadLine();
int number = int.Parse(input);
Console.WriteLine($"入力された数値:{number}");
}
}

数値(例:123)を入力すれば正常に動きます。 しかし、abc のような文字列を入力すると例外が発生 します。

実行例(abc を入力):

整数を入力してください:abc
ハンドルされていない例外: System.FormatException: The input string 'abc' was not in a correct format.
場所 ...

このように、プログラムが途中で強制終了 してしまいました。 発生した例外の名前は FormatException です。


C# には目的別にたくさんの例外クラスが用意されています。 すべてを覚える必要はありませんが、よく出会うものを挙げます。

例外クラス主な発生シーン
FormatExceptionint.Parse などで数値変換に失敗
DivideByZeroException整数を 0 で割った
IndexOutOfRangeException配列の範囲外にアクセスした(第 6 章)
NullReferenceExceptionnull の変数に .プロパティ でアクセスした(第 11 章)
FileNotFoundException指定したファイルが見つからない
IOExceptionファイル入出力で問題が起きた
ArgumentException引数が不正(自分で throw するときにも使える)
InvalidOperationException操作できない状態で処理を呼んだ

例外には種類があり、後で見るように 種類ごとに対応を分けられる のが C# の例外処理の特徴です。


例外処理の基本形は try-catch です。

try
{
// 例外が発生する可能性がある処理
}
catch
{
// 例外が発生したときの処理
}

try ブロックの中で例外が発生すると、その時点で try 内の処理は中断され、catch ブロックへ処理が移ります。 例外が発生しなければ、catch は実行されません。


先ほどのコードを try-catch で囲み、abc を入れてもプログラムが落ちないようにします。

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
Console.Write("整数を入力してください:");
string input = Console.ReadLine();
try
{
int number = int.Parse(input);
Console.WriteLine($"入力された数値:{number}");
}
catch
{
Console.WriteLine("整数に変換できませんでした。");
}
Console.WriteLine("処理を終了します。");
}
}

実行例(abc を入力):

整数を入力してください:abc
整数に変換できませんでした。
処理を終了します。

実行例(123 を入力):

整数を入力してください:123
入力された数値:123
処理を終了します。

例外は発生していますが、catch で受け止めているので プログラム全体は最後まで進みます


catch (Exception ex) の形で書くと、例外オブジェクトを受け取れます。 ex.Message発生した例外の説明文 を取得できます。

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
Console.Write("整数を入力してください:");
string input = Console.ReadLine();
try
{
int number = int.Parse(input);
Console.WriteLine($"入力された数値:{number}");
}
catch (Exception ex)
{
Console.WriteLine("エラーが発生しました。");
Console.WriteLine($"内容:{ex.Message}");
}
Console.WriteLine("処理を終了します。");
}
}

実行例(abc を入力):

整数を入力してください:abc
エラーが発生しました。
内容:The input string 'abc' was not in a correct format.
処理を終了します。

ex.Message の文言は環境やバージョンで多少変わりますが、何が起きたか を教えてくれます。 研修中はこのメッセージで原因を確認できます。

補足:Exception は例外の親玉

Exception は、すべての例外クラスの 親(基底クラス) です。 FormatExceptionIOException も、この Exception を親とする継承関係にあります(継承については第 13 章で扱います)。 catch (Exception ex) は「何でも捕まえる」という意味になります。


15-3 複数の catch で種類別に対応する

Section titled “15-3 複数の catch で種類別に対応する”

try の後ろに catch複数並べる ことができます。 例外の種類に応じて違う処理をしたい場合に使います。

try
{
処理
}
catch (FormatException)
{
数値変換エラーの場合
}
catch (Exception ex)
{
その他のエラーの場合
}

割られる数と割る数を入力し、結果を表示するプログラムです。

  • 数値以外を入力した場合 → FormatException
  • 割る数に 0 を入れた場合 → DivideByZeroException

両方を別々の catch で扱います。

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
try
{
Console.Write("割られる数を入力してください:");
int number1 = int.Parse(Console.ReadLine());
Console.Write("割る数を入力してください:");
int number2 = int.Parse(Console.ReadLine());
int result = number1 / number2;
Console.WriteLine($"計算結果:{result}");
}
catch (FormatException)
{
Console.WriteLine("整数として正しい形式で入力してください。");
}
catch (DivideByZeroException)
{
Console.WriteLine("0 で割ることはできません。");
}
catch (Exception ex)
{
Console.WriteLine("予期しないエラーが発生しました。");
Console.WriteLine($"内容:{ex.Message}");
}
}
}

実行例 1(数値以外を入力):

割られる数を入力してください:abc
整数として正しい形式で入力してください。

実行例 2(0 を入力):

割られる数を入力してください:10
割る数を入力してください:0
0 で割ることはできません。

実行例 3(正常):

割られる数を入力してください:10
割る数を入力してください:3
計算結果:3

複数の catch を書くときは、具体的な例外を先、Exception を後 にします。

// OK
catch (FormatException) { ... }
catch (DivideByZeroException) { ... }
catch (Exception ex) { ... }

逆順に書くと、Exception がすべての例外を捕まえてしまい、後ろの具体的な catch永久に到達しなくなります

// NG
catch (Exception ex) { ... } // ← ここですべて捕まえる
catch (FormatException) { ... } // ← ここには到達しない(警告/エラー)

C# のコンパイラがこのパターンに警告を出してくれます。


15-4 finally で必ず実行する処理

Section titled “15-4 finally で必ず実行する処理”

finally は、try-catch のあとに付ける特別なブロックで、例外が発生してもしなくても、最後に必ず実行されます

try
{
処理
}
catch (Exception ex)
{
例外が発生したときの処理
}
finally
{
必ず実行する処理(後片付け)
}

主な使い道は、後片付け処理です。

ファイルを閉じる
DB 接続を閉じる
ロックを解放する
ログを出す

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
Console.Write("整数を入力してください:");
string input = Console.ReadLine();
try
{
int number = int.Parse(input);
Console.WriteLine($"入力された数値:{number}");
}
catch (FormatException)
{
Console.WriteLine("整数として正しい形式で入力してください。");
}
finally
{
Console.WriteLine("入力処理を終了します。");
}
Console.WriteLine("プログラムを終了します。");
}
}

実行例(正常):

整数を入力してください:123
入力された数値:123
入力処理を終了します。
プログラムを終了します。

実行例(異常):

整数を入力してください:abc
整数として正しい形式で入力してください。
入力処理を終了します。
プログラムを終了します。

正常時も異常時も、「入力処理を終了します。」 が必ず表示されます。


後の DB 接続編では、次のような構造で書くことが多くなります。

DB に接続する
SQL を実行する
結果を読み取る
DB 接続を閉じる ← 例外が出ても忘れたくない

DB 接続は 開いたまま放置すると、サーバー側のリソースが枯渇する など重大な問題になります。 そのため、finally で必ず閉じる、というのが昔からのパターンです。

ただし、現代の C# では using を使って自動で閉じる書き方も使います。 これは第 17 章以降で扱います。


15-5 TryParse で例外を出さずに変換する

Section titled “15-5 TryParse で例外を出さずに変換する”

int.Parse + try-catch で数値変換エラーに対応できますが、入力チェック程度のことに毎回例外を発生させるのは大げさ という考え方もあります。 例外には、内部的に「どこで起きたか」「どう呼ばれたか」などの情報を集める処理が走るため、それなりに重い のです。

そこで、入力チェックには int.TryParse が便利です。

方法失敗時向いている場面
int.Parse例外が発生する入力が正しい前提の内部処理
int.TryParsefalse を返すだけ(例外なし)ユーザー入力のチェック

int.TryParse は、変換に成功したかを bool で返し、変換結果は out パラメータ で受け取ります。

int number;
bool success = int.TryParse(input, out number);
結果successnumber
"123"true123
"abc"false0(初期値)

out は「変換できた値を、この変数に書き込んでください」という指定です。 よく使う書き方として、変数宣言を out の中に書く短縮形もあります。

bool success = int.TryParse(input, out int number);

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
Console.Write("整数を入力してください:");
string input = Console.ReadLine();
if (int.TryParse(input, out int number))
{
Console.WriteLine($"入力された数値:{number}");
}
else
{
Console.WriteLine("整数として正しい形式で入力してください。");
}
}
}

実行例(正常):

整数を入力してください:123
入力された数値:123

実行例(異常):

整数を入力してください:abc
整数として正しい形式で入力してください。

try-catch を使わずに、エラーを処理できました。


正しい数値が入力されるまで再入力させる

Section titled “正しい数値が入力されるまで再入力させる”

while (true) と組み合わせると、正しい数値が入力されるまで何度も聞き直す プログラムになります。

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
int number;
while (true)
{
Console.Write("整数を入力してください:");
string input = Console.ReadLine();
if (int.TryParse(input, out number))
{
break;
}
Console.WriteLine("整数として正しい形式で入力してください。");
}
Console.WriteLine($"入力された数値:{number}");
}
}

実行例:

整数を入力してください:abc
整数として正しい形式で入力してください。
整数を入力してください:12.5
整数として正しい形式で入力してください。
整数を入力してください:42
入力された数値:42

このパターンは、ユーザー入力を扱うコンソールアプリで頻繁に使います。


15-6 throw で自分から例外を発生させる

Section titled “15-6 throw で自分から例外を発生させる”

プログラムの中で、あえて例外を発生させたいことがあります。 たとえば、商品価格にマイナスが指定された場合 ── プログラムとしては明らかに不正です。

このようなときに throw を使います。

throw new ArgumentException("価格にマイナス値は指定できません。");

これは、第 7 章で学んだ new クラス名(...) の形と同じです。例外オブジェクトを作って throw で投げます。


Product クラスで価格をチェックする

Section titled “Product クラスで価格をチェックする”

Product.cs:

Product.cs
namespace Ch15_ExceptionHandling;
class Product
{
public string ProductName { get; private set; }
public int Price { get; private set; }
public Product(string productName, int price)
{
if (price < 0)
{
throw new ArgumentException("価格にマイナス値は指定できません。");
}
ProductName = productName;
Price = price;
}
public string GetDisplayText()
{
return $"{ProductName}:{Price}";
}
}

Program.cs:

Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
try
{
Product product = new Product("ノート", -100);
Console.WriteLine(product.GetDisplayText());
}
catch (ArgumentException ex)
{
Console.WriteLine("引数エラーが発生しました。");
Console.WriteLine($"内容:{ex.Message}");
}
}
}

実行結果:

引数エラーが発生しました。
内容:価格にマイナス値は指定できません。

-100 という不正な価格を渡したので、Product のコンストラクター内で例外が発生し、Main 側の catch で受け止めています。


例外は便利ですが、何でも例外で処理するのはやり過ぎ です。

ユーザーがよく入力ミスをするケース
→ if 文・TryParse で対応する(例外を出さない)
「呼び出し方が間違っている」「ありえない状態」
→ 例外として throw する

たとえば、上記の Product クラスでは、コンストラクターを呼ぶ側が「マイナス価格は渡さない」のが当然です。 それでもマイナスが渡されたら、プログラムの呼び出し方が間違っている ので例外で知らせます。

一方、ユーザーが Console.ReadLine でうっかり数字以外を入力するのは「よくあること」なので、TryParse で淡々とエラー表示すれば十分です。


第 9 章で File.ReadAllLines などを学びました。 ファイル操作では、次のような例外が起こり得ます。

例外発生シーン
FileNotFoundException指定したファイルが見つからない
DirectoryNotFoundException指定したフォルダが見つからない
UnauthorizedAccessExceptionアクセス権がない
IOExceptionその他のファイル入出力エラー(他プロセスが使用中など)

File.Exists で事前確認しても、確認直後に削除される可能性があるため、try-catch での例外対応も併用 するのが安全です。


Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
string filePath = "employee_names.txt";
try
{
string[] lines = File.ReadAllLines(filePath);
foreach (string line in lines)
{
Console.WriteLine(line);
}
}
catch (FileNotFoundException)
{
Console.WriteLine("ファイルが見つかりません。");
}
catch (Exception ex)
{
Console.WriteLine("ファイル読み込み中にエラーが発生しました。");
Console.WriteLine($"内容:{ex.Message}");
}
}
}

実行例(ファイルが存在しない場合):

ファイルが見つかりません。

employee_names.txtbin\Debug\net8.0\ フォルダに置いてから実行すると、内容が表示されます。


Program.cs
namespace Ch15_ExceptionHandling;
internal class Program
{
static void Main(string[] args)
{
string filePath = "app.log";
string text = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} アプリを実行しました。{Environment.NewLine}";
try
{
File.AppendAllText(filePath, text);
Console.WriteLine("ログを書き込みました。");
}
catch (IOException ex)
{
Console.WriteLine("ファイル書き込み中にエラーが発生しました。");
Console.WriteLine($"内容:{ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine("予期しないエラーが発生しました。");
Console.WriteLine($"内容:{ex.Message}");
}
}
}

実行結果:

ログを書き込みました。

IOException を先に書き、その他を Exception で受ける形です。


15-8 DB 接続に向けた例外処理の考え方

Section titled “15-8 DB 接続に向けた例外処理の考え方”

第 17 章以降の DB 接続では、次のような問題が常に起こりえます。

SQL Server が起動していない
接続文字列が間違っている
ユーザー名・パスワードが違う
ネットワーク・サービスの問題
SQL 文の文法ミス、テーブル名・列名の間違い
取得した値が想定と違う(NULL 含む)

DB 接続では、実行時の問題に必ず備える必要があります


実際の DB 接続コードは第 17 章で扱いますが、構造のイメージは次のようになります。

try
{
// DB に接続する
// SQL を実行する
// 結果を読み取る
}
catch (Exception ex)
{
// エラー内容を表示する(またはログに残す)
}
finally
{
// 必要に応じて DB 接続を閉じる
}

using 文を使えば finally を書かずに自動で閉じる書き方もあります(第 17 章で扱う)。

押さえておきたい考え方:

DB 接続は失敗することがある
失敗したときに、プログラムがただ落ちるだけでは困る
エラー内容を確認できるようにする
リソース(接続)は必ず解放する

業務アプリでは例外メッセージを表に出しすぎない

Section titled “業務アプリでは例外メッセージを表に出しすぎない”

研修中は学習のため ex.Message を画面に表示します。 しかし、業務アプリでは利用者にそのまま見せないのが普通 です。

例外メッセージには、次のような情報が含まれることがあります。

接続文字列(サーバー名・ユーザー名)
SQL 文・テーブル名・列名
内部のシステム情報

これが利用者に見えると、システムの内部構造が漏れたり、ユーザーが混乱したりします。 業務アプリでは次のような対応が一般的です。

出力先内容
利用者向け画面「データの取得に失敗しました。管理者に連絡してください。」
開発者向けログ例外メッセージ・スタックトレース・呼び出し元情報

研修では ex.Message を確認しますが、本番想定のときは表示方法を考える、と覚えておきましょう。


つまずき原因対応
例外処理の必要性が分からない正常系だけで考えている入力ミスやファイル不存在を想定する
try の中に何を書くか分からない例外が発生しそうな処理を意識できていない変換、ファイル、DB 接続などを入れる
catch が実行されない例外が発生していない正常時は catch に入らない
catch (Exception) だけにしてしまう例外の種類を分けていない必要に応じて具体的な例外を先に書く
catch の順番でエラーException を先に書いている具体的な例外を先、Exception を後
finally の意味が分からない正常時も異常時も実行されることを知らない後片付け処理を書く場所と覚える
TryParseout が分からない変換結果の受け取り方に慣れていない「成功時に値を入れる箱」と覚える
例外を握りつぶしてしまうcatch だけ書いて何もしない最低限メッセージ表示やログ出力を行う
何でも例外で処理しようとする条件分岐との使い分けが曖昧入力チェックは TryParseif も使う
throw のあとに何か続けて書くthrow でメソッドが終わると気付いていないthrow 以降のコードは到達しない

  • 例外とは何かを説明できる
  • コンパイルエラーと実行時エラーの違いを説明できる
  • try-catch の基本形を書ける
  • FormatExceptionDivideByZeroException などの代表的な例外を説明できる
  • ExceptionMessage を表示できる
  • 複数の catch を順序ルールに従って書ける
  • finally の役割を説明できる
  • int.TryParse を使って安全に数値入力を処理できる
  • int.TryParsewhile で再入力ループを書ける
  • throw で例外を発生させられる
  • ファイル読み書きの例外を処理できる
  • DB 接続で例外処理が重要になる理由を説明できる
  • 業務アプリでは例外メッセージの扱いに注意することを説明できる

研修の進め方によっては、隣の人またはチーム内で説明確認を行います。

次の内容を、自分の言葉で説明してください。

  1. 例外とは何ですか。
  2. try にはどんな処理を書きますか。
  3. catch はいつ実行されますか。
  4. FormatException はどんなときに発生しますか。
  5. finally は何のために使いますか。
  6. int.Parseint.TryParse の違いは何ですか。
  7. throw はどんなときに使いますか。
  8. DB 接続で例外処理が重要になるのはなぜですか。
  9. 業務アプリで例外メッセージをそのまま画面に出さない方がよい理由は何ですか。

説明するときは、完全な答えでなくても構いません。 自分の言葉で説明しようとすることが大切です。


この章の演習課題に取り組みます。

本章では タイマー方式 で進めます。次の 3 段階で取り組んでください。

段階時間内容
① 準備10 分(目安)上の「ペア確認」と、これから取り組む課題(仕様)の読み込み。ペアや講師に質問してよい
② ソロ作業35 分(タイマーで計測)一人で課題に取り組む。タイマーが鳴ったら、完成・未完成にかかわらず作業を止めて提出する
③ チーム時間講師が指定する発表開始時刻までチーム内でコードレビューを行い、発表者を決める。実装の続行も可。時間配分はチームで管理する

評価対象はタイマー時点で提出されたコードです(タイマー後に書き足した分は評価には含まれません)。 発表開始時刻は厳守 です。チーム時間中も、その時刻が来たら全員手を止めて発表に移ります。

演習の進め方の詳細は、付録A「演習の進め方」 を参照してください。


課題はソリューション Kadai15 の中に作成してください。 課題ごとに別のプロジェクトを作成 し、指定されたプロジェクト名を使います。

課題必須/発展プロジェクト名作成する主なファイル
課題 15-1必須Kd15_01_TryCatchBasicProgram.cs
課題 15-2必須Kd15_02_MultipleCatchProgram.cs
課題 15-3必須Kd15_03_TryParseInputProgram.cs
課題 15-4発展Kd15_04_RetryInputProgram.cs
課題 15-5発展Kd15_05_ProductThrowProgram.csProduct.cs
課題 15-6発展Kd15_06_FileExceptionProgram.cs

フォルダ構成は次のようになります。

Kadai15/ ← 課題用ソリューションフォルダ
Kadai15.sln
Kd15_01_TryCatchBasic/
Kd15_02_MultipleCatch/
Kd15_03_TryParseInput/
Kd15_04_RetryInput/
Kd15_05_ProductThrow/
Kd15_06_FileException/

補足:ソリューションに複数のプロジェクトを追加する方法

最初の課題で Kadai15 ソリューションと Kd15_01_TryCatchBasic プロジェクトを同時に作成します。

2 つ目以降の課題は、ソリューションエクスプローラーで Kadai15 を右クリックし、追加新しいプロジェクト から追加します。


以下は、本章のすべての課題に共通する作業です。各課題の本文には繰り返し書きません。

作業内容参照
プロジェクト作成時の設定最上位レベルのステートメントを使用しない」にチェック第 1 章 1-1
csproj の編集<Nullable>disable</Nullable> に変更第 1 章 1-1
namespace の書き方ファイルスコープ形式(namespace XXX;)で書く第 7 章 冒頭
クラスファイルの追加ソリューションエクスプローラーでプロジェクトを右クリック → 追加クラス(課題 15-5 の Product.cs など)第 7 章 7-7
ファイルを保存して実行Ctrl + S で保存 → F5 で実行第 1 章 1-2

特に 2 つ目以降のプロジェクトも、新規追加するたびに csproj の Nullable を disable に変更する 必要があります。

提出ルール(タイマー方式)

35 分のタイマーが鳴ったら手を止め、git addcommitpush を行います。評価対象はタイマー時点のコミットのみです(タイマー後の追加は評価外)。

Chapter15 タイマー提出: <どこまで完成> / <詰まったポイント>

例:Chapter15 タイマー提出: 15-1〜15-2完成、15-3は途中 / TryParse の out の書き方で詰まった

サーバへコピー提出の場合

Git 不調で講師指示があれば、push の代わりに Kadai15 フォルダをサーバへコピーし、提出先に 提出メモ.txt を作成します(内容:どこまで完成 / 詰まったポイント)。

タイマー後のチーム時間

発表開始時刻まで、コードレビュー / 発表者選出 / 実装続行(任意・評価外)。時間配分はチームの判断、発表開始時刻は厳守


まずは、全員が必須課題に取り組んでください。


課題 15-1 try-catch で数値変換エラーに対応する

Section titled “課題 15-1 try-catch で数値変換エラーに対応する”

整数を入力し、int.Parse で変換するプログラムを try-catch で囲んでください。 数値以外が入力された場合は、エラーメッセージを表示して、プログラムは正常に終了するようにしてください。

実行例(正常):

整数を入力してください:123
入力された数値:123
処理を終了します。

実行例(異常):

整数を入力してください:abc
整数として正しい形式で入力してください。
処理を終了します。

条件:

  • try-catch を使う
  • catch (FormatException) を使う
  • 例外発生後も「処理を終了します。」が表示されること

課題 15-2 複数の catch + finally で割り算

Section titled “課題 15-2 複数の catch + finally で割り算”

2 つの整数を入力し、割り算の結果を表示してください。 次の場合をそれぞれ別の catch で処理し、最後に finally で必ずメッセージを表示してください。

状況例外表示するメッセージ
数値以外を入力FormatException「整数として正しい形式で入力してください。」
割る数に 0 を入力DivideByZeroException「0 で割ることはできません。」
その他のエラーException「予期しないエラーが発生しました。」 + ex.Message
必ず(なし)finally で「計算処理を終了します。」

実行例(正常):

割られる数を入力してください:10
割る数を入力してください:3
計算結果:3
計算処理を終了します。

実行例(0 入力):

割られる数を入力してください:10
割る数を入力してください:0
0 で割ることはできません。
計算処理を終了します。

条件:

  • catch (FormatException)catch (DivideByZeroException)catch (Exception ex)順番 を守る
  • finally で必ず終了メッセージを出す

課題 15-3 TryParse で安全に数値入力する

Section titled “課題 15-3 TryParse で安全に数値入力する”

int.TryParse を使って、整数を 1 つ入力するプログラムを作成してください。 try-catch は使わないでください。

実行例(正常):

整数を入力してください:42
入力された数値:42

実行例(異常):

整数を入力してください:abc
整数として正しい形式で入力してください。

条件:

  • int.TryParse(input, out int number) を使う
  • if (...) { ... } else { ... } で分岐する
  • try-catch使わない

必須課題が終わった人は、発展課題に取り組んでください。 発展課題からは、仕様だけが提示されます。実装方法は自分で考えてください。


課題 15-4 正しい年齢が入力されるまで再入力させる

Section titled “課題 15-4 正しい年齢が入力されるまで再入力させる”

ユーザーから「年齢」を入力してもらうプログラムを作成してください。 正しい範囲の整数(0 以上 150 以下)が入力されるまで、何度でも聞き直すようにします。

仕様

  • メッセージは「年齢を入力してください:」
  • 入力チェック:
    • 整数に変換できない場合 → 「整数として正しい形式で入力してください。」
    • 0 未満または 150 超 → 「0 以上 150 以下で入力してください。」
  • 正しく入力できたら「入力された年齢:N」と表示して終了

実装ヒント

  • while (true) + int.TryParse + if で範囲チェック
  • 範囲外なら continue で再入力に戻す

実行例:

年齢を入力してください:abc
整数として正しい形式で入力してください。
年齢を入力してください:200
0 以上 150 以下で入力してください。
年齢を入力してください:25
入力された年齢:25

課題 15-5 Product クラスで不正な価格を例外にする

Section titled “課題 15-5 Product クラスで不正な価格を例外にする”

商品を表す Product クラスを別ファイル(Product.cs)で作成し、コンストラクターで価格をチェックしてください。 価格がマイナスの場合は ArgumentException を投げ、Main 側で catch してください。

Product クラス仕様

  • ファイル名:Product.cs
  • プロパティ:ProductName (string)、Price (int)、どちらも get; private set;
  • コンストラクター:Product(string productName, int price)
    • price < 0 なら throw new ArgumentException("価格にマイナス値は指定できません。");
  • メソッド:GetDisplayText()"{ProductName}:{Price}円" を返す

Main メソッド仕様

  • try ブロックの中で、次の 2 通りを順に実行する
    1. new Product("ノート", 180) を作成して表示
    2. new Product("消しゴム", -50) を作成して表示(ここで例外発生)
  • catch (ArgumentException ex) でエラーメッセージを表示

実行結果例:

ノート:180円
引数エラーが発生しました。
内容:価格にマイナス値は指定できません。

課題 15-6 ファイル読み書きの例外処理

Section titled “課題 15-6 ファイル読み書きの例外処理”

employee_names.txt を読み込んで内容を表示し、その後 app.log に「読み込み完了:現在日時」を追記するプログラムを作成してください。 ファイル操作で起こりうる例外を、複数の catch で適切に処理します。

仕様

  • 読み込みフェーズ:
    • File.ReadAllLines("employee_names.txt") で読み込む
    • 全行を foreach で表示
    • FileNotFoundException → 「ファイルが見つかりません。」
    • その他の例外 → 「読み込み中にエラーが発生しました。」+ ex.Message
  • 書き込みフェーズ:
    • File.AppendAllText("app.log", $"読み込み完了:{DateTime.Now:yyyy/MM/dd HH:mm:ss}{Environment.NewLine}")
    • IOException → 「ログ書き込み中にエラーが発生しました。」+ ex.Message
    • その他の例外 → 「予期しないエラーが発生しました。」+ ex.Message
  • それぞれ別の try-catch で書く(1 つの大きな try にまとめない)
  • 最後に finally で「処理を終了します。」と表示する try-catch-finally を全体の外側に書く必要はない(各フェーズの try-catch の後に普通に書けば OK)

事前準備

bin\Debug\net8.0\ フォルダに employee_names.txt を作成し、社員名(山田二郎、佐藤昭夫、山口洋子 など)を 3 行書いておく。 ファイルがない状態でも実行して、FileNotFoundException の動きも確認すること。

実行例(ファイル有):

山田二郎
佐藤昭夫
山口洋子
ログを書き込みました。
処理を終了します。

実行例(ファイル無):

ファイルが見つかりません。
ログを書き込みました。
処理を終了します。

  • プログラムを Visual Studio から実行できる
  • try-catch を使えている
  • FormatExceptionDivideByZeroException を使い分けている(必須 15-2)
  • catch の順序ルール(具体例外を先)を守れている
  • finally を使えている(必須 15-2)
  • int.TryParse を使えている(必須 15-3)
  • whileTryParse で再入力ループを書けている(発展)
  • throw で例外を発生させている(発展)
  • ファイル例外(FileNotFoundExceptionIOException)を処理している(発展)
  • 例外メッセージを ex.Message で確認している
  • インデントが整っている
  • 課題を提出した(Git の commitpush、または講師指示があれば Kadai15 フォルダをサーバへコピーし、提出先フォルダに 提出メモ.txt を作成)

タイマーが鳴ったら、第 15 章の課題プロジェクト群(Kadai15 ソリューション)をその場で Git に提出します。

Terminal window
git status
git add .
git commit -m "Chapter15 タイマー提出: <どこまで完成> / <詰まったポイント>"
git push origin main

実行例:

Terminal window
git commit -m "Chapter15 タイマー提出: 15-1〜15-3完成、15-4は途中 / 範囲チェックの再入力ループで詰まった"

Git の詳しい操作は 付録 C、コミットメッセージ形式とサーバコピー提出は本章冒頭「演習課題 > 提出ルール」を参照してください。


この章では、例外処理を学習しました。

  • 例外 は、プログラムの実行中に発生する問題
  • 例外の種類:FormatExceptionDivideByZeroExceptionFileNotFoundExceptionIOException など
  • try-catch で例外を捕まえ、プログラムが落ちないようにできる
  • catch (Exception ex) で例外オブジェクトを受け取り、ex.Message で内容を確認できる
  • 複数の catch を書けるが、具体的な例外を先・Exception を後 にする
  • finally は、例外の有無にかかわらず最後に必ず実行される(後片付けに使う)
  • int.TryParse を使えば、例外を出さずに変換可否をチェックできる
  • int.TryParse + while で、再入力させる定番パターンを書ける
  • throw new ArgumentException(...) で自分から例外を発生させられる
  • 例外と if 文の使い分け:よくある入力ミスは TryParse、ありえない状態は例外
  • ファイル操作・DB 接続では例外処理が 必須 になる
  • 業務アプリでは、例外メッセージをそのまま利用者に見せない配慮も重要

次章からは、いよいよ データベース を扱います。

まず第 16 章では、研修で使うデータベースの 土台づくり を行います。SQL Server Management Studio(SSMS)を使って、研修用データベース TrainingDB とテーブルを作成し、サンプルデータを投入します。 続く第 17 章で、C# のコンソールアプリから TrainingDB に接続し、この章で学んだ try-catch-finally と、新しく学ぶ using 文を組み合わせて、安全に DB を操作するパターンを身に付けます。

第 7 章から学んできたクラスやメソッド、そして本章の例外処理が、ここから一気に実用シーンで活きてきます。