C#で例外が発生した場合でも処理を実行するコードの記述について紹介します。
概要
C#で例外が発生した場合にも処理を実行したい場合には、finally ブロックを利用します。finallyブロックを利用することで、tryブロック内で処理が完了した場合、例外が発生してcatchブロックが実行された後に、finallyブロック内のコードが実行されます。
プログラム例 - Catch,Finallyを実装した例外処理の場合
UI
下図のフォームを作成します。フォームにTextBoxを1つ、Buttonを1つ配置します。
コード
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace FinallyDemo
{
public partial class FormFinally : Form
{
public FormFinally()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string file = "data.txt";
StreamReader sr = new StreamReader(file, Encoding.GetEncoding("SHIFT_JIS"));
try {
while (sr.EndOfStream == false) {
string line = sr.ReadLine();
int value = Convert.ToInt32(line);
textBox_Output.Text += Convert.ToString(value * 2) + "\r\n";
}
}
catch (FormatException fe) {
textBox_Output.Text += "形式が不正です。\r\n";
}
finally {
sr.Close();
}
}
}
}
解説
StreamReader を利用して、実行ファイルと同じ場所に配置してある、"data.txt"ファイルを開きます。ファイルを開いた後、ReadLineメソッドを呼び出しファイルを1行ずつ読み取ります。読み出した内容を数値に変換し、その数値を2倍した値をテキストボックスに表示します。
ファイルの中に数値でない行があった場合、数値への変換に失敗し、FormatException例外が発生します。例外はcatchブロックで受け取り、テキストボックスに"形式が不正です。"のメッセージを表示します。
また、finallyブロックを記述し、StreamReaderのCloseメソッドを記述します。この記述により、tryブロック内の処理が完了した場合、または例外の発生によりcatchブロック内の処理が実行された後にfinallyブロックの処理が実行されます。finallyブロックにより、正常に処理が完了した場合でも、例外が発生した場合でも確実にStreamReaderのCloseメソッドを呼び出し、ファイルを閉じます。
テキストファイル (data.txt)
プログラムから読み込まれるテキストファイルを作成します。
data.txt : 正常なファイル
6
8
12
4
9
data.txt : 異常なファイル
6
Penguin
12
Duck
9
実行結果
プロジェクトを実行します。下図のフォームが画面に表示されます。
正常な"data.txt"ファイルを配置して、[button1]をクリックします。テキストファイルの数値の2倍の数値がテキストボックスに表示されます。
続いて、異常な"data.txt"ファイルを配置して、[button1]をクリックします。2行目に数値でない行があるため、数値変換に失敗し、「形式が不正です。」のメッセージがテキストボックスに表示されます。
"data.txt"のファイルを開いて、下記に修正します。修正後ファイルが保存できることを確認します。(後述するfinallyを利用しないコードではファイルが開いたままになるため、保存ができない状態になります。)
保存後、[button1]をクリックします。"data.txt"が再度読み込まれ処理が実行されます。3行目まで数値の行のため、4行目で数値変換に失敗し、「形式が不正です。」のメッセージが表示されます。
プログラム例 - 例外処理がない場合
例外処理を全く記述しない場合、どのような動作になる確認してみます。
UI
下図のUIを作成します。[TextBox]と[Button]を1つずつ配置します。
コード
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace FinallyDemo
{
public partial class FormNonFinally : Form
{
public FormNonFinally()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string file = "data.txt";
StreamReader sr = new StreamReader(file, Encoding.GetEncoding("SHIFT_JIS"));
while (sr.EndOfStream == false) {
string line = sr.ReadLine();
int value = Convert.ToInt32(line);
textBox_Output.Text += Convert.ToString(value * 2)+"\r\n";
}
sr.Close();
}
}
}
解説
先のコードと同様の処理になりますが、 try catch finally いずれの例外処理も記述しないコードになります。例外が発生した場合、アプリケーションは終了する動作になります。
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。
正常な"data.txt"ファイルを配置して、[button1]をクリックします。テキストファイルの数値の2倍の数値がテキストボックスに表示されます。
続いて、異常な"data.txt"ファイルを配置して、[button1]をクリックします。2行目に数値でない行があるため、数値変換に失敗し、例外が発生します。catchブロックが無いため、例外が発生したタイミングでIDEのデバッガが停止します。
デバッガが停止している状態で、"data.txt"ファイルを開きます。
ファイルを変更して保存しようとすると、「プロセスはファイルにアクセスできません。別のプロセスが使用中です。」のダイアログが表示されファイルが保存できません。
なお、デバッガが無い状態で直接実行ファイルを起動した場合は、下図の「アプリケーションのコンポーネントで、ハンドルされていない例外が発生しました。」のメッセージが表示されアプリケーションが強制終了します。
プログラム例 - catchのみの例外処理を記述した場合
catchの例外処理を記述し、finallyを記述しない場合、どのような動作になる確認してみます。
UI
下図のUIを作成します。[TextBox]と[Button]を1つずつ配置します。
コード
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace FinallyDemo
{
public partial class FormCatch : Form
{
public FormCatch()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string file = "data.txt";
StreamReader sr = new StreamReader(file, Encoding.GetEncoding("SHIFT_JIS"));
try {
while (sr.EndOfStream == false) {
string line = sr.ReadLine();
int value = Convert.ToInt32(line);
textBox_Output.Text += Convert.ToString(value * 2) + "\r\n";
}
sr.Close();
}
catch (FormatException fe) {
textBox_Output.Text += "形式が不正です。\r\n";
}
}
}
}
解説
先のコードと同様の処理になりますが、 try catch の例外処理を記述しています。例外が発生した場合、catchブロックにて処理が実行され、テキストボックスに"形式が不正です。" のメッセージが表示されます。例外がハンドリングされるため、アプリケーションは強制終了にはなりません。finally ブロックが記述されていないため、例外発生後にはファイルは開かれたままとなります。
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。
正常な"data.txt"ファイルを配置して、[button1]をクリックします。テキストファイルの数値の2倍の数値がテキストボックスに表示されます。
続いて、異常な"data.txt"ファイルを配置して、[button1]をクリックします。2行目に数値でない行があるため、数値変換に失敗し、例外が発生しますが、catchブロックが記述されているため、アプリケーションは停止せず、デバッガの例外メッセージは表示されません。catchブロック内の処理により、テキストボックスに「形式が不正です。」のメッセージが表示されます。
上記の「形式が不正です。」のメッセージが表示された後、data.txtファイルを開き、ファイルを編集し保存を実行すると、下図の「プロセスはファイルにアクセスできません。別のプロセスが使用中です。」のメッセージが表示されファイルを保存できません。例外の発生によりファイルのクローズ処理が実行できず、ファイルが開いたままになっていることが確認できます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2017-11-14
作成日: 2017-07-21