例として、あるテキストファイルの1行目に書かれている文字列を10進数とみなして取り込む、という関数を考えてみます。
ここで例外が送出される状況には、1.何らかの理由でファイルを開けない(EFOpenError)、2.ファイルが空(0行)だった(EFileIsEmpty)、3.1行目に10進数に変換できない文字があった(EConvertError)の3つがあります(正確にはリソース不足でTStringList.Createが失敗する状況を含め4つですが、今回は考えないことにします)。それぞれの原因に対応した例外クラスがあるため、呼び出し元ではエラーの理由を例外オブジェクトのクラスの違いで知ることができます。
ここでエラーメッセージにファイル名を表示したい、ということになったとします。ところが呼出元のレベルではファイルの存在するパスはわかっていますがフルパス名はReadIntegerValueFromFileの内部に隠蔽されてしまっています。そこで
とすることで
のようにエラーがあったときにそのファイルのフルパス名を知ることができます。が、エラーの原因はわからなくなってしまいました。そこで例外チェーンの登場です。クラスプロシージャException.RaiseOuterExceptionを使用することで、その例外ハンドラで受け取った例外オブジェクトを消滅させることなく新たな例外を送出することができます。
ここで送出される例外オブジェクトはEFileReadErrorのままです。しかし
と例外オブジェクトのInnerExceptionプロパティでException.RaiseOuterExceptionを呼び出した時点での例外オブジェクトを参照することができます。
この例外チェーンに関係するメソッド、プロパティには
- RaiseOuterException: 例外ブロック内で使用し、新しく生成した例外オブジェクトをパラメータとして呼び出すことでその時点での例外オブジェクトをチェーンした例外を送出するExceptionクラスのクラスプロシージャ。
- ThrowOuterException: RaiseOuterExceptionと同じ。C++では例外はraiseするものではなくthrowするものなのでこの名前のクラスプロシージャも用意されている。
- InnerException: 最も近いRaiseOuterExceptionを送出した時点での例外オブジェクトを格納しているプロパティ。通常の例外の送出(raise EXXXX.Create)ではnilとなる。またRaiseOuterExceptionがネストして呼び出されている場合はE.InnerException.InnerException...のようにさかのぼって例外オブジェクトを参照することができる。
- BaseException: ネストしてRaiseOuterExceptionが呼び出された場合に最初に送出された例外オブジェクトを格納しているプロパティ。通常の例外の送出(raise EXXXX.Create)ではnilとなる。また1段階しかRaiseOuterExceptionが呼び出されていない場合はInnerException=BaseExceptionとなる。
- ToString例外チェーン上の全ての例外オブジェクトのMessageプロパティをCR+LFで連結したプロパティ。
元ねたはDELPHI 2009 HANDBOOK。
0 件のコメント:
コメントを投稿