# こういうことを知ったかぶって言うと、「当たり前だろヴォケ」とか「今まで知らなかったの!?」とか言われそうな気がして、ちょっと怖いのだけど。
# というか、.NET Frameworkの挙動がどうなっているか調べずに書いてる。
イベントって何だろう? →何らかのアクションが発生したことを通知する機構。
例外って何だろう? →何らかの操作が、その責務を完了できなかったことを報告する機構。
イベントの処理中に例外が発生するということは、何を意味するんだろう?
例外が発生したということは、その処理は責務を完了できなかったことを示す。
けれど、イベントの責務は「通知すること」だから、イベントが発生した時点で、既にその責務は果たされている。
失敗したのは、イベントの発生を受けて走る処理であって、イベントそのものではない。
だから、イベント(を駆動するOnXXXメソッド)は、例外を外部に伝播させるべきではない?
別の方向から考えてみる。
イベントの実体はMulticastDelegateであり、これには複数のハンドラを結びつけることができる。
この時、各々のハンドラが呼び出される順番は保証されないのではないだろうか。
だとすると、イベントの発生順を期待した処理を組んではならないということになる。つまり、各イベントハンドラは独立しており、他のイベントハンドラと何ら関連性を持たない。
ということは、あるイベントが失敗したところで、他のイベントには関係ないのだから、他のイベントは正常に呼び出されなければならない。
ここから、イベントハンドラ中で発生した例外は握りつぶすべきである、という結論に至る。
さらに別の方向から考えてみる。
Windowsはイベント駆動型OSであり、それはメッセージの送信によって実現されている。
メッセージ送信には、同期と非同期、SendMessageとPostMessageがある。
.NETのイベントとWindowsのイベントが必ずしもイコールとなるわけではないけれど、イベントハンドラがウィンドウプロシージャから呼び出されるとすれば、PostMessageによってポストされたメッセージの処理中に例外が発生した場合、その例外はPostMessageの呼び出し元では捕捉できない。
じゃあその例外はどこに飛んでいくかと言えば、(Windowsの構造化例外処理に従えば)メッセージループを飛び出してスレッドを終了させてしまう(これを捕捉する最終手段、スレッドプロシージャ全体に仕掛けられたハンドラがApplication.ThreadExceptionなのだろう、たぶん)。
よって、(Windowsメッセージによって駆動される)イベントでは、例外を発生させるべきではない。
しつこく別の方向から考えてみる。
イベントの実体はデリゲートである。であれば、何故デリゲートだけでなく、イベントという機構がわざわざ用意されたのだろう?
この2つは、仕組み的には同じである。ならば、意味的に違うのではないか?
イベントの意味が「発生した時点で責務を全うするもの」ではないかということは既に書いた。
そして、非同期処理(Stream.BeginReadとか)で使われるデリゲートで発生した例外は、一旦保留され、その処理を完了するタイミング(Stream.EndReadとか)に中継されるようになっている。
つまり、イベントではないデリゲートでは、例外を発生させてはならないということはない。
イベントとデリゲートには、例外処理に関して意味的な違いがあるのではないだろうか。だからこそ、わざわざイベントというものを用意したのではないだろうか。