連載
» 2002年12月19日 00時00分 公開

連載 改訂版 C#入門:第18章 例外とエラー処理 (4/4)

[川俣晶(http://www.autumn.org/),(株)ピーデー(http://www.piedey.co.jp/)]
前のページへ 1|2|3|4       

18-9 例外を再発生させてのエラー処理

 ただ単に例外をキャッチして処理を行うだけでは不十分な場合がある。例えば、1つの例外について、別々の階層のメソッド内の別々のcatch文でエラー処理を行う必要が生じる場合がある。このような場合、catchブロック内で、さらにもう一度同じ例外を発生させる必要が出てくる。このようなケースでは専用の構文が使用できる。List 18-12はそれを使用したサンプル・ソースである。

  1: using System;
  2: using System.IO;
  3: using System.Text;
  4:
  5: namespace Sample010
  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:   }
 19:   class Class1
 20:   {
 21:     private static void sample()
 22:     {
 23:       try
 24:       {
 25:         DelayedFileReader reader = new DelayedFileReader("存在しない.txt");
 26:       }
 27:       catch( FileNotFoundException e )
 28:       {
 29:         Console.WriteLine( "Class1.sampleでFileNotFoundException例外を確認しました。" );
 30:         throw;
 31:       }
 32:     }
 33:     [STAThread]
 34:     static void Main(string[] args)
 35:     {
 36:       try
 37:       {
 38:         sample();
 39:       }
 40:       catch( FileNotFoundException e )
 41:       {
 42:         Console.WriteLine( "Class1.MainでFileNotFoundException例外を確認しました。" );
 43:       }
 44:     }
 45:   }
 46: }

List 18-12

 これを実行するとFig.18-10のようになる。

Fig.18-10

 List 18-12では、15行目で発生する例外を27行目からのcatchブロックでキャッチしているが、ここでキャッチしなければ40行目からのcatchブロックでもキャッチされるはずのものである。両方でエラー処理を行いたい場合は、27行目からのcatchブロック内でもう一度同じ例外を発生させ、40行目からのcatchブロックに実行するチャンスを与える必要がある。そのために、例外を再発生させているのが30行目のthrow文だが、見てのとおり、同じ例外を再発生させる場合は例外インスタンスを指定する必要はない。

18-10 例外クラスを自作する

 例外で使用するクラスは、Exceptionクラスを継承していればよい。つまり、自分でExceptionクラスを継承したクラスを作れば、それも利用できる。実際に記述してみた例がList 18-13である。

  1: using System;
  2: using System.IO;
  3: using System.Text;
  4:
  5: namespace Sample011
  6: {
  7:   class MyException : Exception
  8:   {
  9:     public MyException( string message ) : base( message )
 10:     {
 11:     }
 12:   }
 13:   class Class1
 14:   {
 15:     [STAThread]
 16:     static void Main(string[] args)
 17:     {
 18:       throw new MyException("自作例外");
 19:     }
 20:   }
 21: }

List 18-13

 これを実行するとFig.18-11のようになる。

Fig.18-11

 Fig.18-11を見て分かるとおり、MyExceptionはシステムから例外の一種として認知されており、問題なくコンソールに情報が出力されている。Exceptionクラスには3つのコンストラクタがあるが、よく使われるのは文字列の引数が1個のものである。これは9行目のように、引数をちゃんと親クラスに渡してやらないとエラーになってしまうので、そのように記述する必要がある。それ以外は、プログラマーが必要だと思う機能をこのクラスに書き加えてよい。

 このような自作例外クラスを用意すると自作プログラム内のエラー処理を円滑に行える場合もあるので、覚えておくとよいだろう。例え、自作例外クラス内に機能らしい機能が必要とされていないとしても、例外を区別できるというだけでメリットがある場合も多い。

18-11 例外クラスのインスタンスを活用する

 いうまでもなく、例外クラスのインスタンスはインスタンスであるからメソッドやプロパティを持つ。Exceptionクラスには有益な情報を得られるメソッドやプロパティがあるので、それを使ってみよう。List 18-14を見てほしい。

  1: using System;
  2:
  3: namespace Sample012
  4: {
  5:   class Class1
  6:   {
  7:     [STAThread]
  8:     static void Main(string[] args)
  9:     {
 10:       try
 11:       {
 12:         throw new Exception("Sample");
 13:       }
 14:       catch( Exception e )
 15:       {
 16:         Console.WriteLine(e.Message);
 17:         Console.WriteLine();
 18:         Console.WriteLine(e.Source);
 19:         Console.WriteLine();
 20:         Console.WriteLine(e.StackTrace);
 21:         Console.WriteLine();
 22:         Console.WriteLine(e.TargetSite);
 23:         Console.WriteLine();
 24:         Console.WriteLine(e.ToString());
 25:       }
 26:     }
 27:   }
 28: }

List 18-14

 これを実行するとFig.18-12のようになる。

Fig.18-12

 List 18-14の16行目以降とFig.18-12を対比しながら見ていただきたい。まず、Messageプロパティは、例外発生時に指定されたメッセージを持つ。Sourceプロパティは例外の起きたプログラムの名前(正確にはアセンブリの名前)を持つ。場合によってはオブジェクトの名前になる場合もあるようだ。StackTraceはメソッドの呼び出された順番を示す文字列を持つ。例外をキャッチしないときに表示される、メソッドを羅列する文字列である。TargetSiteプロパティは、例外の発生したメソッドの情報を持つ。最後のToStringメソッドはシステムが例外の内容をコンソールに出力する場合と同じ書式の文字列を返す。もし、ログファイルなどに例外の情報を保存しておきたい場合は、このメソッドで情報を取得して、それをファイルに保存するようにするとよいだろう。

18-12 さまざまな例外

 システムに含まれる主立った例外をTable 18-1に紹介する。

例外 意味
System.OutOfMemoryException メモリを使い切った
System.StackOverflowException スタックがあふれた
System.NullReferenceException nullへの参照にアクセスしようとした
System.TypeInitializationException staticなコンストラクタが例外を発生させたが、だれもキャッチしなかった
System.InvalidCastException キャストの間違い
System.ArrayTypeMismatchException 配列の型が合わない
System.IndexOutOfRangeException 添え字の範囲から外れている
System.ArithmeticException 数値演算エラー(ゼロ除算やオーバーフローなど)
System.DivideByZeroException ゼロ除算
System.OverflowException オーバーフロー
Table 18-1

 念のために補足すると、ゼロ除算はArithmeticExceptionとDivideByZeroExceptionの両方でキャッチできるように読めるのは、そのとおりである。DivideByZeroExceptionはArithmeticExceptionを継承しているので、ArithmeticExceptionをキャッチしようとすれば、自動的にDivideByZeroExceptionもキャッチ可能になるのである。OverflowExceptionも事情は同じである。このように例外クラスを階層化してカテゴライズするのも、例外をエレガントに使う戦略の1つである。

『新プログラミング環境 C#がわかる+使える』
 本記事は、(株)技術評論社が発行する書籍『新プログラミング環境 C#がわかる+使える』から許可を得て一部分を転載したものです。

【本連載と書籍の関係について 】
 この書籍は、本フォーラムで連載した「C#入門」を大幅に加筆修正し、発行されたものです。連載時はベータ版のVS.NETをベースとしていましたが、書籍ではVS.NET製品版を使ってプログラムの検証などが実施されています。技術評論社、および著者である川俣晶氏のご好意により、書籍の内容を本フォーラムの連載記事として掲載させていただけることになりました。

技術評論社の解説ページ

ご注文はこちらから


「連載 改訂版 C#入門」のインデックス

連載 改訂版 C#入門

前のページへ 1|2|3|4       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。