NAgilerの日記 - Agile Principles, Patterns, and Practices in C# (^o^)
なんと、書籍「アジャイルソフトウェア開発の奥義」の C# 版だそうです
ほ、ほしぃ・・・。でも洋書読めない ;-;
邦訳版が出てくれることを祈ります ( できれば、アジャイルソフトウェア開発の奥義と同じ人の翻訳で ^^ )
# よく見たらけっこう前 ( 2006年8月 ) に出てたんですね、知らなかった ^^;
例外について見てみる。基本クラスでスローするとされていない例外は、LSP により、派生クラスでもスローしてはいけないことになる。
ここで言う "基本クラスでスローするとされていない例外" とは "基本クラスでスローしない例外" ではない。.NET なら XML コメントの <exception> セクションで宣言されていない例外のことを指している。Java は詳しくないけど Java なら throws で宣言されていない例外。 ( ※ )
これを逆に言えば、基本クラスではスローしなくとも、派生クラスでスローされる可能性があるのなら、基本クラスで宣言しなければならないということになる。でなければ LSP に違反してしまう。
ここで注意しなければいけないのが、例外の抽象度だと思う。
例えば、書籍データをデータストアから取得するための GetBookData メソッドが IBookFinderインターフェイスに定義されているとする。
IBookFinder インターフェイスを利用するアプリケーションは今の所 2 つあるとする。片方はデータストアとして XML ファイルを利用し、BookFinderFromXml クラスが IBookFinder インターフェイスを実装している。もう片方はデータストアとして DB を利用し、BookFinderFromDB クラスが IBookFinder インターフェイスを実装している。
BookFinderFromXml クラスの GetBookData メソッドは、XML ファイルが見つからなかった時に FileNotFoundException をスローする。
一方、BookFinderFromDB クラスの GetBookData メソッドは、DB が見つからなかった時に DBNotFoundException をスローする ( こんな例外 .NET に用意されていないけど )。
では、IBookFinder インターフェイスの GetBookData メソッドにはこれらの例外がスローされる可能性があると宣言するのかというと、それは違う。そんなことしてたら、派生クラスが増えるたびに、IBookFinder インターフェイスに修正をすることになるかもしれない。
ここで抽象度が出てくる。例えば DataStoreNotFoundException といった例外クラスを定義し、IBookFinder インターフェイスの GetBookData メソッドでは、この例外をスローすると宣言するべきである。派生クラスでは、FileNotFoundException や DBNotFoundException の代わりに、この例外、またはこの例外を派生させた例外 ( DataStoreFileNotFoundException とか ) をスローできる。
ちなみに、LSP に準拠させる前の BookFinderFromXml クラスは FileNotFoundException をスローしていたが、FileNotFoundException のこういう使い方は不適切な気がする。LSP とか関係なく、FileNotFoundException ではなく「データストアが存在しない」という意味の例外をスローすべきだと思う。
LSP を適用することで、この点も解消されている所が面白い。
なお、この例で挙げた設計は、僕がこの記事を書くために適当に考えただけの設計であり、実際の業務アプリには適用できない ( または適用すべきでない ) 設計かもしれない。クラス名も適当だし。あくまでも LSP と例外について書きたかっただけなので。
※ .NET と Java では例外の扱い方に大きな差があります。ここでは .NET の <exception> セクションと Java の throws を並べてますが、全く性質の異なるものです。
セッションの格納方法別に挙動をまとめてみました。 ( SQL Server モードは未検証ですが。。。 )
[ In Process モード ]
未処理例外発生時の HTTP リクエスト処理より以前にセッションデータが格納されていた場合、セッションはクリアされません。
未処理例外発生時の HTTP リクエスト処理より以前にセッションデータが格納されていなかった場合、未処理例外発生時の HTTP リクエスト処理中に格納されたセッションは、未処理例外発生時の HTTP リクエスト処理が終了した時点でクリアされます。
[ State Server モード ]
未処理例外発生時の HTTP リクエスト処理中に格納されたセッションデータは、未処理例外発生時の HTTP リクエスト処理が終了すると無効化され、未処理例外発生時の HTTP リクエスト処理以前の状態が復元されます。 ( 新しくキーを生成した場合は削除され、既存のキーに対してなんらかの処理を行った場合は、その処理が全て取り消される。 )
[ SQL Server モード ]
検証してません。 ( State Server モードと同じ動作な予感。 )
どのみち、Global.asax の Error イベントハンドラでリダイレクトすればセッションは保持されます。Global.asax で ClearError メソッドを呼び出すことで例外が「処理」されるため、上記動作が作動しないということですね。
# この検証をしている時に ClearError メソッドを呼び忘れて検証していたため、「Global.asax でリダイレクトさせても同様の現象が発生する!」って内容の記事を30分程公開していたのは内緒 ^^; もしその時に記事を読んでしまった方がいらっしゃいましたら、本当にすみませんでした m( _ _;)m
Web.config で上記のようにして defaultRedirect を設定した場合、未処理の例外が発生したら自作エラーページである Error.aspx にリダイレクトされます。
僕の場合は、今まで Global.asax の Error イベントハンドラ ( Application_Error メソッド ) で自作エラーページへのリダイレクト処理を行っていました。なので気づかなかったんですが、Web.config に設定した defaultRedirect によってエラーページに遷移した場合、セッションがクリアされます。
Global.asax の Error イベントハンドラでリダイレクトさせるより defaultRedirect でリダイレクトさせた方がいいんじゃないか?と疑問に思って ( ※ ) 検証していたら、これに気づきました。いや、気づくまでしばらくハマってました。
今後も Global.asax の Error イベントハンドラでリダイレクトしていこうと心に決めましたね。
※ defaultRedirect でリダイレクトさせる場合、mode 属性に RemoteOnly 指定するだけで簡単に開発者向けのエラーページを表示するように切り替えられるからです。
[ 関連記事 ]
未処理例外発生時のセッションの動作
日経BP書店|商品詳細 - プログラミングMicrosoft ADO.NET 2.0
定価は 8,925 円 とやや高めですが、MCP 資格を保有している人は以下のページにて 10% OFF の 8,033 円 で購入できます。
プログラミング Microsoft ADO.NET 2.0 ( 日経BPソフトプレス )
これはもう買うしかないですね。僕は財布と相談もせずに注文してしまいました ^^;
[ 情報元 ]
The road to C# master trapemiya
# あれ、Windows Live ID にサインインしていなくても、割引が適用されるんだけど・・・。
# もしかして MCP 資格持ってなくても割引価格で購入できんの・・・?