深い階層からの例外
例外の発生場所とキャッチする場所は、必ずしも同じメソッド内に存在しなくてもよい。そのメソッドを呼び出しているメソッドでもよいし、さらにそのメソッドを呼び出しているメソッドでもよい。以下はそれを示したサンプルである。
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クラスのインスタンスを生成して指定している。もちろん、どんな例外クラスでもここで利用できる。
Insider.NET 記事ランキング
本日
月間