連載

C#入門

第18回 例外とエラー処理

(株)ピーデー
川俣 晶
2001/12/22


例外とは何か?

 比較的新しいプログラム言語を使っている方々には、例外は使い慣れた定番の機能と言えるだろう。しかし、少し古いプログラム言語には、例外の機能がないことも多いので、今回はそのような言語に慣れたプログラマ向けに例外を解説してみたい。

 例外は、処理の流れで特殊な状況が発生したときに起こる状況である。一般的には、各種エラー発生時などに例外は発生する。例外を発生することを「例外を投げる」ともいう。まずは、実際に例外が起きる事例を見ていただこう。以下は、存在しないファイルを開こうとするサンプル・プログラムだ。当然、正常に動作はしない。

 1: using System;
 2: using System.IO;
 3: using System.Text;
 4:
 5: namespace ConsoleApplication34
 6: {
 7:   class Class1
 8:   {
 9:     static void Main(string[] args)
10:     {
11:       StreamReader reader = new StreamReader("存在しない.txt",Encoding.GetEncoding("Shift_JIS"));
12:       Console.Write( reader.ReadToEnd() );
13:       reader.Close();
14:     }
15:   }
16: }
例外を発生させるサンプル・プログラム1
「存在しない.txt」というファイル名のファイルを開こうとしている。

 これを実行すると以下のようになる。

サンプル・プログラム1の実行結果
プログラムを実行すると、例外が発生したことを知らせるメッセージが出力される。
  例外の内容
  スタック・トレース

 「未処理の例外」という文字列から、下から2行目の「line 11」までが例外によって出力されたメッセージである。これらのメッセージは例外が起きたことを報告するメッセージであって、例外そのものではない。「未処理の例外」から以下3行が例外の内容を伝えている。その下はスタック・トレースと呼ばれているもので、下から順番に読むものである。この例外が発生したのは、Mainメソッドから呼ばれたStreamReaderのコンストラクタ(「ctor」という表記になっている)から呼ばれた引数違いのコンストラクタの……、と繰り返し、最終的に“WinIOError”というクラスが発生源だと分かる。しかし、実際に自分で書いたのはMainメソッドだけなので、Mainメソッド内で何かトラブルが起きたと理解すればよいだろう。つまり、Mainメソッドから呼び出したStreamReaderクラスのコンストラクタで、何らかの問題が生じたと理解すればよい。具体的な問題の内容は最初の3行に示されているとおりで、ファイルが見つからなかったのである。

例外と他の方法を比較する

 ファイルが見つからないときにどう対処するか、C言語とVisual Basci 6.0で記述したサンプル・ソースと比較してみよう。まずはC言語から。

 1: #include <stdio.h>
 2:
 3: int main(int argc, char* argv[])
 4: {
 5:   FILE * fp = fopen("存在しない.txt","r");
 6:   if( NULL == fp ) {
 7:     perror( "存在しない.txt" );
 8:     return 2;
 9:   }
10:   while(1) {
11:     int ch = fgetc(fp);
12:     if( ch == -1 ) break;
13:     putchar(ch);
14:   }
15:   fclose(fp);
16:   return 0;
17: }
C言語によるサンプル・プログラム2
fopen関数でファイルを開こうとしている。ファイルがオープンできたかどうかはfopen関数の戻り値でチェックする。

 このサンプル・ソースのポイントは、6行目にある。5行目のfopen関数で開こうとしたファイルが存在しなかった場合、fopen関数はNULLを返すので、6行目のif文がエラーの発生を判断する。もし、if文を取り去ってしまうと、プログラムはエラー状態のまま実行を続け、正常な結果を出力しないまま終わるだろう。

 次はVisual Basic 6.0の場合だ。

 1: Private Sub Form_Load()
 2:   Dim s As String
 3:   On Error GoTo errorHandler
 4:   Open "存在しない.txt" For Input As #1
 5:   On Error GoTo 0
 6:   Do
 7:     If EOF(1) Then Exit Do
 8:     Line Input #1, s
 9:     Debug.Print s
10:   Loop
11:   Close 1
12:   Exit Sub
13: errorHandler:
14:   If Err = 53 Then
15:     MsgBox "ファイルが見つかりません。"
16:   Else
17:     MsgBox "ファイルが開けません。"
18:   End If
19: End Sub
Visual Basic 6.0によるサンプル・プログラム3
ファイルがオープンできなかった場合には“On Error GoTo”文によりジャンプする。

 ここでポイントになるのは、3行目の“On Error GoTo”文だ。これは、エラー発生時に実行すべきラベルを指定する機能である。もし、4行目のOpen文でファイルが見つからなかった場合、3行目の設定により、処理は13行目以降にジャンプする。このときもし、3行目がなければ、システムがエラー・メッセージを出力する。C言語のようにチェックするためのIf文は必要なく、チェックしなくてもエラー状態のまま実行が続くことはない。

 では、これらとほぼ同等の機能をC#で記述するとどうなるだろうか。

 1: using System;
 2: using System.IO;
 3: using System.Text;
 4:
 5: namespace ConsoleApplication35
 6: {
 7:   class Class1
 8:   {
 9:     static void Main(string[] args)
10:     {
11:       try
12:       {
13:         StreamReader reader = new StreamReader("存在しない.txt",Encoding.GetEncoding("Shift_JIS"));
14:         Console.Write( reader.ReadToEnd() );
15:         reader.Close();
16:       }
17:       catch( FileNotFoundException e )
18:       {
19:         Console.WriteLine("ファイル" + e.FileName + "が見つかりません。");
20:       }
21:     }
22:   }
23: }
C#言語によるサンプル・プログラム4
try文とcatch文のペアにより、ファイルがオープンできなかった場合の処理を記述する。

 これを実行すると以下のようになる。

サンプル・プログラム4の実行結果
例外発生のメッセージは出力されず、ファイルのオープンができない場合のエラー・メッセージが正しく表示されている。

 見てのとおり、ここにはif文はない。つまり、C言語のように、プログラマがエラーが発生したかどうかの判定をいちいち挿入する必要はない、ということだ。その点で、C言語よりもVisual Basicのスタイルに近い。ここでは、try文とcatch文のペアが、エラー発生時の動作を指定する手段を実現している。tryの後のブロック({ }の範囲内)には、エラーが起こるかもしれないコードを記述する。そして、catchの後のブロック中に、エラーが起こった場合の動作を記述する。13行目でファイルを開こうとしているが、ファイルが見つからない場合、即座に19行目に処理が移り、メッセージがコンソールに出力される。もし、try文とcatch文がなければ、最初のサンプルのように、システムが自動的にコンソールに情報を出力してプログラムを中断して終了する。

 C#では、このようなエラーなどを例外と呼ぶ。try文は例外が発生するかもしれないコードを指定する役割を持ち、try文とペアで記述されるcatch文が、実際に発生した例外をつかまえて処理する役割を持つ。17行目のcatch文の括弧内に“FileNotFoundException e”と記述されているが、“FileNotFoundException”はクラス名で、“e”は引数の名前である。発生した例外的な状況には、それぞれ対応するクラスがあり、そのインスタンスが渡される。インスタンスには有益な情報が入っている。例えば、FileNotFoundExceptionはファイルが見つからないという状況を示すクラスで、見つからなかったファイルのファイル名を含むFileNameプロパティを持っている。これを使って適切なエラー・メッセージを組み立てることができる。

 

 INDEX
  第18回 例外とエラー処理
  1.例外とは何か?
    2.例外を区別して扱う
    3.確実な終了処理を行うfinally
    4.深い階層からの例外
    5.例外処理の再発生
    6.例外クラスのインスタンスを活用する
 
「C#入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間