連載

C#入門

第18回 例外とエラー処理

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


深い階層からの例外

 例外の発生場所とキャッチする場所は、必ずしも同じメソッド内に存在しなくてもよい。そのメソッドを呼び出しているメソッドでもよいし、さらにそのメソッドを呼び出しているメソッドでもよい。以下はそれを示したサンプルである。

 1: using System;
 2: using System.IO;
 3: using System.Text;
 4:
 5: namespace ConsoleApplication41
 6: {
 7:   class Class2
 8:   {
 9:     public void fileRead( string fileName )
10:     {
11:       StreamReader reader = null;
12:       try
13:       {
14:         reader = new StreamReader( fileName, Encoding.GetEncoding("Shift_JIS") );
15:         Console.Write( reader.ReadToEnd() );
16:       }
17:       catch( FileNotFoundException e )
18:       {
19:         Console.WriteLine( e.FileName + "が見つかりません。" );
20:       }
21:       finally
22:       {
23:         if( reader != null )
24:         {
25:           reader.Close();
26:         }
27:       }
28:     }
29:   }
30:   class Class1
31:   {
32:     private static void test()
33:     {
34:       Class2 instance = new Class2();
35:       try
36:       {
37:         instance.fileRead( "存在しない\\存在しない.txt" );
38:       }
39:       catch( DirectoryNotFoundException e )
40:       {
41:         Console.WriteLine( "ディレクトリが見つかりません。" );
42:       }
43:     }
44:     static void Main(string[] args)
45:     {
46:       try
47:       {
48:         test();
49:       }
50:       catch( Exception e )
51:       {
52:         Console.WriteLine( e.GetType().FullName + "の例外が発生しました。" );
53:       }
54:     }
55:   }
56: }
別のメソッドで例外をキャッチするサンプル・プログラム10
Class2ではDirectoryNotFoundExceptionの例外をキャッチしていない。Class2のインスタンスを使用しているClass1で、その例外をキャッチしている。

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

サンプル・プログラム10の実行結果
別のメソッドで発生した例外が正しく処理されているの分かる。

 これを実行すると、14行目のStreamReaderクラスのコンストラクタがDirectoryNotFoundExceptionの例外を発生させる。コンストラクタは12行目からのtryブロック内にあるものの、この例外をキャッチするcatch文はないので、ここではキャッチされない。そこで、このメソッドを呼び出したメソッドを調べる。つまり、32行目からのtestメソッドである。ここで、問題のメソッドは37行目から呼び出されているが、これは35行目からのtryブロック内にある。このブロックに付随する39行目のcatch文がまさにDirectoryNotFoundExceptionクラスの例外をキャッチするcatch文なので、このcatch文が有効になり、41行目が実行される。もし、ここでもキャッチされない例外の場合は、46行目からのtryブロックに付随する50行目のcatch文でキャッチされることになる。50行目はExceptionクラスなので、すべての例外はここでキャッチされる。しかし、階層が低い方が優先されるので、より低い階層でチェックされるFileNotFoundExceptionクラスやDirectoryNotFoundExceptionクラスは、それぞれのcatch文でキャッチされる。

 このように、エラー処理は発生したメソッド内で行う必要はない。同じようなエラーが発生しうる個所が多い場合は、それらの呼び出し元のメソッド内で、一括して処理することもできる。

ユーザー・プログラムが発生させる例外

 例外はシステムのライブラリが発生させると決まったものではない。ユーザー・プログラム内に、例外を発生させるコードを書くこともできる。例えば、以下は、実際に読み出すまでファイルのオープンを遅らせる機能を書き込んだクラスである。オープンは遅らせるが、ファイルが存在しない場合はコンストラクタを実行した段階で例外が起きてほしいとしよう。

 1: using System;
 2: using System.IO;
 3: using System.Text;
 4:
 5: namespace ConsoleApplication42
 6: {
 7:   class DelayedFileReader
 8:   {
 9:     private string _fileName;
10:     public DelayedFileReader( string fileName )
11:     {
12:       _fileName = fileName;
13:       if( !File.Exists( fileName ) )
14:       {
15:         throw new FileNotFoundException( "ファイルが見つかりません。", fileName );
16:       }
17:     }
18:     public string ReadToEnd()
19:     {
20:       StreamReader reader = null;
21:       try
22:       {
23:         reader = new StreamReader(_fileName,Encoding.GetEncoding("Shift_JIS"));
24:         return reader.ReadToEnd();
25:       }
26:       finally
27:       {
28:         if( reader != null )
29:         {
30:           reader.Close();
31:         }
32:       }
33:     }
34:   }
35:   class Class1
36:   {
37:     static void Main(string[] args)
38:     {
39:       DelayedFileReader reader = new DelayedFileReader("存在しない.txt");
40:       Console.Write( reader.ReadToEnd() );
41:     }
42:   }
43: }
例外を生成するサンプル・プログラム11
15行目にあるように、throw文によりユーザーのプログラムからも例外を発生させることができる。

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

サンプル・プログラム11の実行結果
catch文がないため、コンソールに例外の内容が表示される。例外の種類に続いて表示される文字列はthrow文で設定したものだ。

 13行目のFile.Existsメソッド(フルネームはSystem.IO.File.Exists)は、ファイルが存在するかどうかを判定するメソッドである。もし開きたいファイルがない場合は、FileNotFoundExceptionクラスの例外を発生させる。ここでポイントになるのは、15行目の“throw”文だ。throw文は例外を発生させる。例外の内容は、throwのキーワードのあとに記述する値になる。通常は、例外のクラスをnewによってインスタンス生成して指定する。ここでは、FileNotFoundExceptionクラスのインスタンスを生成して指定している。もちろん、どんな例外クラスでもここで利用できる。


 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 記事ランキング

本日 月間