例外が発生した場合でも処理を実行する - finally ブロックの利用 - C#

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
iPentec all rights reserverd.