僕はやはり、
「業務エラーは例外で表現するべき」
と考えます。
では、その理由について語っていきます。
【 目次 】
1. 例外の利点
2. 業務エラーとしての例外
3. 注意点
4. まとめ
5. 参考文献
【 用語 】
この記事で使用する用語について、以下のように定義します。
・例外
System.Exceptionから派生する全ての例外クラスを指します。
・エラー
正常系ではないフローを指します。エラーは業務エラーとシステムエラーに大別できます。
・業務エラー
エンドユーザーの操作次第で発生しうるエラーを指します。
業務を遂行する上で間違った操作をエンドユーザーが行った場合に発生するエラーや、エンドユーザーが操作を行っている間に、他のエンドユーザーが何らかの操作を行ったことによって、現在の操作が有効でなくなった場合に発生するエラーなどです。
・システムエラー
システム異常やネットワーク異常、プログラムの欠陥など、エンドユーザーに非がないエラーを指します。
【 1. 例外の利点 】
業務エラーとかシステムエラーとかはひとまず置いといて、まずは「エラー」を例外で表す場合の利点を挙げてみます。
- 例外時の処理コードを分離できる
- バグを検出しやすい
- 詳細な情報を保持している
それぞれ見ていきましょう。
[ 1-1. 例外時の処理コードを隔離できる ]
構造化例外処理は、その名が表すように、「例外処理コードを分離・隔離」することによって「構造化」します。つまり、可読性、保守性に優れるということです。
エラーを戻り値で表す場合はどうでしょうか?
これは、if文やswitch文を用いて処理コードを分離することができます。
しかし、確実に構造化例外処理より劣ります。
構造化例外処理なら、例えば例外をスローする可能性のあるメソッドを呼び出す時、例外が発生したとしても呼び出し元で特に処理する必要がなければ、呼び出し元には例外に関するコードを一切記述する必要がありません。例外はそのまま上位へと伝わり、適切な箇所で処理が行われます。
[ 1-2. バグを検出しやすい ]
例外はハンドルされなければCLRに検出されます。また、ハンドルし損ねた例外を最上位 ( ASP.NETで言えばGlobal.asaxのエラーハンドラ ) で全てハンドルし、ログを残すといったことも可能です。
僕の場合、この最上位のハンドラで例外を検出したら、「予期しない例外が発生しました。」というようなメッセージをエンドユーザーに見せて、裏ではログを残すという手法をよく使います。
エラーが戻り値で帰ってきた場合、そのエラーを適切に処理しなくても、CLRには当然検出されません。すると、どこかで不整合が生じます。その結果アプリケーショ ンがおかしな挙動を起こしたとしても、何が原因なのかは例外に比べて判別がつきづらくなります。また、アプリケーションが ( 一見すると ) 正常な動作を続けてしまうかもしれません。その場合、バグを検出することは困難になります。
[ 1-3. 詳細な情報を保持している ]
デバッグの最中にハンドルされない例外が発生した場合、その例外の各プロパティを参照すれば色々な情報を得ることができます。具体的には、どんな例外なのか ( 型やMessageプロパティ ) 、どのアセンブリで発生したのか ( Sourceプロパティ ) 、どのメソッドで発生したのか ( TargetSiteプロパティ ) 、どういう経緯で発生したのか ( StackTraceプロパティ ) 、例外の元となった例外について ( InnerExceptionプロパティ ) 、といった情報となります。
先ほど書いたように、ハンドルされなかった例外が発生したら例外の情報をログに残すようにすれば、運用時に発覚したバグも調べやすくなります。
エラーを戻り値で表した場合、これらの情報を取得するのは言うまでもなく大変困難です。
【 2. 業務エラーとしての例外 】
ここまでで、例外の利点について見てきました。これらは全て、業務エラーを例外で表した場合にも適用される利点です。
ここからは、業務エラーとしての例外について別の視点から考察していきます。
[ 2-1. 一つのメソッドは一つの機能を表す ]
例えば、「DBへの反映を行うメソッド」があったとします。
このメソッドは「DBへの反映を行うメソッド」であり、「DBへ反映できるようなら反映するメソッド」ではありません。
このメソッドは、楽観同時実行制御を行います。つまり、他者が先にDBを更新していた場合、DBへの反映は行えず、業務エラーとなります。
業務エラーは、一般的に想定されるエラーと見なされます。しかし、想定されるエラーだからと言って戻り値で返してはいけません。想定されていようがいなかろうが、DBへの反映を行うメソッドでDBへの反映ができないのであれば、それは紛れもない「例外的事象」なのです。
「じゃあメソッド名を変えれば良い」と思うかもしれません。例えば先ほど挙げた 「DBへ反映できるようなら反映するメソッド」 というメソッド名でしょうか?でもこれ、一つのメソッドで二つの機能を表してますね。可能であるかどうかを調べ ( 検証 ) 、可能であればHogeを反映 ( 実行 ) するわけです ( 内部のロジックがどうであれ使う側にしてみればそうなります ) 。構造化の観点からすると、一つのメソッドが複数の機能を表すのはよろしくありません。
では、実行用のメソッドの他に検証用のメソッドを用意すればいいかというと、一概にそうとは言えません。
基本的に検証用メソッドは、例外発生のコストによるパフォーマンスの低下が無視できない状況であったり、前もって検証を行いたい理由がある場合 ( これは業務エラーの表現方法に非依存 ) に用意します。
なお、検証メソッドは検証結果を戻り値で返します。検証メソッドは、言うまでもなく検証を行うためのメソッドなので、結果を戻り値で返すのは自然 ( 当然 ) なことです。
[ 2-2. コスト ]
例外にはコストがかかります。
でも、基本的には問題にならないはずです。
例えば、DBの更新を非接続型データアクセスにて行う場合楽観同時実行制御が行われます。この時、他者が既にDBの更新を行っていたために更新に失敗した場合、これは業務エラーとなります。でもこれ、そう頻繁に発生することではありません ( 頻繁に発生するのなら楽観同時実行制御では不適切です ) 。頻繁に発生しない業務エラーで多少レスポンスが悪くても、それは問題にはならないでしょう。
では頻繁に発生する業務エラーがあったとします。これも問題にはなりません。2-1にて前述したように、「例外発生のコストによるパフォーマンスの低下が無視できない状況」では、検証用のメソッドを用意するからです。
例えば、エンドユーザーからの入力値の妥当性検証は必ず行います。エンドユーザーからの入力値が不正な値であることは ( 故意であろうがなかろうが ) よくあることです。入力値の妥当性検証は、パフォーマンスの向上以外にも、可読性の大幅な向上にも繋がります。
ちなみに、入力値の妥当性を検証した後の処理では、入力値は必ず妥当であるはずですので、もし検証した後の処理で入力値が妥当でないことが検出された 場合、それは業務エラーではなくシステムエラーとなります。これを表す例外クラスは、大抵の場合 ArgumentException クラス、またはその派生クラスとなります。
【 3. 注意点 】
ここまでで、業務エラーを例外で表すことの素晴らしさを語ってきました。
次に、業務エラーを例外で表す際の注意点をいくつか挙げます。
[ 3-1. 適切な実装の上で必要となるのは判別情報のみ ]
判別情報、つまり例外の場合は型です。各業務エラーに応じた適切な例外クラスを用意し、それぞれをハンドルできるようにします。
Exception クラスの持つ各プロパティ ( Exception.Message プロパティや Exception.StackTrace プロパティ ) は、業務エラーが適切に処理されている限り利用することはありません。例えば、 Exception.Message プロパティをそのままエンドユーザーに表示したりしてはいけません。例外クラスの持つ各プロパティを利用するのは、例外の処理漏れ ( ハンドルされない例外の発生 ) があった場合となります ( デバッガやログファイルを通して参照します ) 。
なお、これらは業務エラー・システムエラー問わず言える事です。 ( システムエラーの場合、SQLException.Numberプロパティなど、型以外に判別情報を提供している場合もありますが。。。 )
[ 3-2. 業務エラーはExceptionクラスから派生 ]
Microsoftは以前、アプリケーション固有の例外はApplicationExceptionから派生させることを推奨していました。しかし、現在はこれを推奨していません。変わりにExceptionから派生させることを推奨しています。
なぜでしょうか?これは、Microsoftに原因があります。
Microsoftはこのようなルールを推奨しようとしていました。
- CLRがスローする例外は SystemException クラス (System) 派生の例外
- アプリケーションがスローする例外は ApplicationException クラス (System) 派生の例外
しかし、.NET Framework クラスライブラリ ( 以降、FCL ) 自身がこのルールを守れなかったのです。実は、FCLに用意されている例外の中には、ApplicationExceptionから派生しているクラスや、Exceptionクラスから直接派生しているクラスが紛れ込んでいます。FCLがルールを守れていない以上、このルールはもう台無しです。ApplicationExceptionから派生させる意味はなくなります。
【 4. まとめ 】
- 業務エラーは例外としてスローし、上位で適切な処置を行う必要があります。
- 業務エラーを例外で表すことにより、可読性・保守性の向上に繋がります。
- 業務エラーを例外で表しても、適切な設計を行えばパフォーマンスに問題はありません。
- 業務エラーを表す例外に対して適切な処理を行っている限り、型以外の例外情報は不要です。
- 業務エラーを表す例外がハンドルされなかった場合、例外情報がとても重宝します。
- 業務エラーを表す例外はException クラスから派生させます。
【 5. 参考文献 】
プログラミング Microsoft .NET Framework 第2版
この記事を書くに当たって、この書籍の例外に関するページが大変参考になりました。業務エラー・システムエラーという観点では特に書かれていませんが、是非一読してみることをお勧めします。
(いつも参考にさせて頂いております。初めてコメントさせて頂きます。)私も.NETの例外については随分と悩まされました。Javaでの例外の扱いはもっとすっきりしていますが、.NETでの業務エラーは、やはり"戻り値"で扱わなければならないと思われます。今回の事例については、私としては"業務エラー"ではなく元々"例外"として扱われるべきものではないかと思います。SQLException.Numberは、逆に例外の一部を業務エラーとして処理できるようにある機能だと思います。"戻り値として"扱うとする典型的事例は、祖結合の典型であるWeb ServiceのSOAPExceptionの存在です。SOAP"機能拡張"でも使用しなければAPPサーバで発生した例外を一元的にハンドリングすることができません。すべて例外で処理することを想定しているのなら、"機能拡張"を使用しなくてもよいように提供(設計)されるはずだからです。外部キー制約違反や、一意キー制約は業務フロー上想定しているかで、例外とも、業務エラーとも扱われると赤間さん、AAfNは暗に言っていると解釈しています。正常系、業務エラー合わせてフォローするのが"例外"と考えます(システム上はエラー(例外)を想定するわけですが)。また、業務エラーも基本的には検証用メソッドの形を取るものだと思います。如何でしょうか?
2007.02.26 12:12 URL | kato #- [ 編集 ]
katoさん、初めまして!
コメントありがとうございます
> Javaでの例外の扱いはもっとすっきりしていますが
検査例外のことですね
僕はJavaはほとんど経験ないので、あまり語れないのですが
検査例外の特徴は以下の2点だと思います
・スローされる可能性があり必ずハンドルされるべき例外を明示できる
・スローされる可能性があり必ずハンドルされるべき例外のハンドルを強制できる
C#に検査例外があったら、業務エラーは検査例外で表すでしょう
でも、検査例外がないから業務エラーを例外で表してはいけないというのは、どうかなと思うんです
例外と戻り値を比較すると、
確かに例外は、ドキュメントやUML図、XMLコメントなど、プログラム以外の手段でしか
業務エラーの存在を伝える手段がありません ( 個人的にはそれで充分と考えますが )
戻り値は発生しうる業務エラーを明示できるので処理漏れの可能性は低いかもしれません
でも、結局は処理漏れが発生する可能性があることには変わりません
業務エラーの表現力に関して、完璧ではないにしろ戻り値の方が優れていることは確かです
しかし、そもそもエラーを表現するという本質的な点に関しては、遥かに例外の方が優れています
戻り値の業務エラーとしての表現力が完璧でない以上、エラーの表現力は無視できません
これらを天秤にかければ、エラーとしての表現力が勝ると考えます
業務エラーを表すという点で欠けているからといって、
エラーを表す点で欠けているという点を無視してはいけないと考えます
> 今回の事例については、私としては"業務エラー"ではなく元々"例外"として扱われるべきものではないかと思います。
今回の事例というのは 2-1 で挙げた楽観同時実行制御の例のことでしょうか?
これはもしかしたら人によって意見の別れる所かもしれません。
僕の考える業務エラーは、冒頭の 【 用語 】 で記述したとおりなので、
これも業務エラーに含まれると考えます
> SQLException.Numberは、逆に例外の一部を業務エラーとして処理できるようにある機能だと思います。
僕の考えとしては、Numberプロパティで判別情報を提供するのではなく、
SQLExceptionを派生させるなりしてもう少し細分化するべきだと思ってます
型情報ではなくプロパティで提供することによるメリットは僕には見出せません
> "戻り値として"扱うとする典型的事例は、祖結合の典型であるWeb ServiceのSOAPExceptionの存在です
> SOAP"機能拡張"でも使用しなければAPPサーバで発生した例外を一元的にハンドリングすることができません
> すべて例外で処理することを想定しているのなら、"機能拡張"を使用しなくてもよいように提供(設計)されるはずだからです
う~ん、Soapの仕様がそうだったからという理由は、少々危険な気がします。
また、Webサービスの例外機構は、Webサービスの疎結合という性質ゆえに、位置付けが少し異なると思います
なお、Soap拡張仕様を使わずとも、SoapException.Codeプロパティを使ってエラーの判別情報を指定することが可能です
> 正常系、業務エラー合わせてフォローするのが"例外"と考えます(システム上はエラー(例外)を想定するわけですが)。
すみません、ちょっとよくわからなかったです
"正常系、業務エラー合わせてフォローするのが" の後は戻り値の間違いでしょうか?
> また、業務エラーも基本的には検証用メソッドの形を取るものだと思います。
それは業務エラーを例外で表さないという考えが前提のお話でしょうか?
それとも、僕のように業務エラーを例外で表すという考えが前提のお話でしょうか?
後者だったら、よければ理由も聞きたいです
2007.02.27 01:04 URL | よこけん #Ay6tTHf6 [ 編集 ]
Katoです。ご返答ありがとうございます。
>(割愛)でも、検査例外がないから業務エラーを例外で表してはいけないというのは、どうかなと思うんです
私が第一に考えていることは、『予め想定(定義)された業務エラーには例外を使用しないということ』は、.NET上の制約ではないかということです。ゆえに、(現在は).NETの機能を最大限活かすためにそれに沿って考えようとしています。ですので、例外の持っている機能(良さ)を否定しようと思っているわけではありません。むしろ、『例外(Exception)脳の作り方』にかぶれてそれを無理やり.NETに持ち込もうと格闘していた時期があったくらいですので(笑)。
.NETの"例外"はシステム上(論理上)では想定されるエラーも含まれますが、予め想定されないエラーを処理するためにあるものと理解しています。"業務エラー"というものは予め想定されていますので、フロー上にも記述でき、広義でいえば正常系に含まれるものと言えます(考えます)。
>(割愛)結局は処理漏れが発生する可能性があることには変わりません
その通りだと思います。ですので、そのような可能性のある箇所に対しては、正常系(処理)、業務エラー(処理)を包含する形で例外(処理)を施すと考えます。また、業務エラーは、予め想定されていますのでもともと多くの情報を必要としないはずです。
>(割愛)> 今回の事例については、私としては"業務エラー"ではなく元々"例外"として扱われるべきものではないかと思います。
表現が乱暴でした。
正しくは、"例外"と断定せず、楽観同時実行により起こる状況を"業務エラー"として扱うかというビジネス上の判断により、SQLExceptionでキャッチして、"業務エラー"として処理すべきか、そのまま"例外"として処理すべきか決まるものだと思います。
>(割愛)型情報ではなくプロパティで提供することによるメリットは僕には見出せません
恐らく、上記のような場合で使用されるものと考えます。私はSqlExceptionクラス設計者が何を意図してそのように実装したのかを考え(想像し)、それを最大限有効に活用しようと考えています。仮に、それが私個人の意に反し、またスマートではないと思えても、です。
#クラス設計思想を暴露するような本があれば、面白いと思うのですけれど。そのように.NETのクラスを観察すると理路整然としない、人間くささを感じることが時々ありますが、それはそれで便利だと理解することがほとんどです。
>(割愛)判別情報を指定することが可能です
失礼致しました。例としてはあまりよくなかったと思います。最近Webサービスを結合にに使用することが多かったものですから。
#ご指摘を受けて思い出しました。SoapException.Codeは利用できますが、当時Exception の「型」の代わりに「エラーコード」を使うというのはどうでしょうか、ともめました(苦)。
>(割愛)すみません、ちょっとよくわからなかったです
>"正常系、業務エラー合わせてフォローするのが" の後は戻り値の間違いでしょうか?
フォローとは、try{}でくくるという意味です。私は.NETではこのよう扱えと考えています(ほぼ引用)。(結局一番のより所は赤間本『.NET エンタープライズ Web アプリケーション開発技術大全 Vol.3 ASP.NET 応用編』です。)
業務エラーと例外の分類は
・業務エラー
業務設計で想定されている範囲で処理が分岐する正常終了でないケース。
⇒戻り値として表現
・アプリケーション/システムエラー
業務設計で想定しない異常のため正常終了できないケース。
⇒例外で表現
設計時に「業務エラー」と「アプリケーション/システムエラー」の分類を的確に行い、その上で実装しなければならない。
状況によっては、「業務エラー」を「アプリケーション/システムエラー」に切り替えたり、「アプリケーション/システムエラー」を「業務エラー」に切り替えるコードが必要になる場合がある。
ですので、キャッチした例外から戻り値を返すことも(その逆も)ありだと考えています。
2007.02.27 11:59 URL | Kato #gGM1FPIg [ 編集 ]
こんばんわ、よこけんです
コメントありがとうございます^^
> .NETの"例外"はシステム上(論理上)では想定されるエラーも含まれますが、予め想定されないエラーを処理するためにあるものと理解しています。
> "業務エラー"というものは予め想定されていますので、フロー上にも記述でき、広義でいえば正常系に含まれるものと言えます(考えます)。
本文の2-1で書きました通り、私の考えは "想定されていようがいなかろうが、DBへの反映を行うメソッドでDBへの反映ができないのであれば、それは紛れもない「例外的事象」" という考えです。
この点に関して、「更に検証メソッドを必ず用意して業務フローを確立する」というのであればまだわかるのですが、戻り値で表すというのは完全にNGです。
この理由一つで戻り値を否定する充分な根拠になると考えますがどうでしょう?
また、例外とは、操作レベルの例外的事象を表すのであって、業務フローどうこうは無関係と考えます。強いて言えば、例外 ( 業務エラー ) も最終的にはプレゼンテーション層で適切にハンドルされ、「業務フロー」に乗っかるわけですし。
現にJavaでは例外 ( 検査例外 ) で表します。
> そのような可能性のある箇所に対しては、正常系(処理)、業務エラー(処理)を包含する形で例外(処理)を施すと考えます。
どのような処理を施すのでしょうか?戻り値を判定するswitchブロックのdefault句で例外をスローするとかでしょうか?
例えば、当初業務エラーが発生しないと考えていたメソッドで、業務エラーが発生するとわかり、戻り値の型をvoidから列挙体Aにしたとします。そして、それを受け取って処理する側の変更作業が抜けてしまった場合、処理の施しようがないかと思います。また、これを検出するのは本文 1-2 に書きましたように困難なことです。
> また、業務エラーは、予め想定されていますのでもともと多くの情報を必要としないはずです。
例外は、処理漏れが生じた際にそれを検出しやすくするようにと考えられたものだと思います。そしてその際、その処理漏れについての詳細な情報を提供するために、例外は色々な情報を保持しています。
つまり、処理漏れの可能性がある以上、例外の持つ情報が不要となることはないと考えます。
> 結局一番のより所は赤間本『.NET エンタープライズ Web アプリケーション開発技術大全 Vol.3 ASP.NET 応用編』です。
僕の場合はプログラミング Microsoft .NET Framework 第2版ですね^^;
ちなみにこの本では、例としてある口座からある口座へ指定した金額を移動させるメソッドを取り上げています。そして戻り値の型はvoidとし、「戻った場合は成功、失敗した場合は例外をスロー」としています。そして、移動元の口座の残高が不足しているためお金を移動できない等のケースは例外として扱うと明示しています。
> 正しくは、"例外"と断定せず、楽観同時実行により起こる状況を"業務エラー"として扱うかというビジネス上の判断により、SQLExceptionでキャッチして、"業務エラー"として処理すべきか、そのまま"例外"として処理すべきか決まるものだと思います。
うーん、そもそもAAfNと赤間本では業務エラーの考え方が違うんですよね。AAfNでは、想定される・されないという区別はしていません。
本文の 【用語】 を見てもらえばわかるとおり、私も想定される・されないという区別はしていません。
赤間本を読んで「業務エラーを戻り値で表そう」という意見を持たれている方々は、恐らく想定する・しないで業務エラーを区別しているかと思います。なので、本文 2-1 ではそれを少し取り上げました。「業務エラーは一般的に想定されるエラーと見なされる」という言い回しもそのためです。
しかし、そもそも想定される・されないというのは、処理を行うメソッドが判断するのではなく、利用者側が判断することです。
例えば、ビジネス層をコンポーネント化し、これをいくつかのアプリケーションから利用するとします。この時、その状況を想定する・しないは各アプリケーションに委ねられます。何がいいたいかというと、その状況が想定されるべき状況であるかどうかを決めるのは各アプリケーションであって、ビジネスコンポーネントが決めていいことではないんじゃないでしょうか?
この例えはわかりやすく説明するためにビジネス層をコンポーネント化した場合を取り上げましたが、当然コンポーネント化に関わらず言える事です。
2007.02.28 00:25 URL | よこけん #Ay6tTHf6 [ 編集 ]
こんにちは。通りすがりですが、意見など。
基本的には「業務エラーは例外で返す」に一票です。
根拠としては以下の二点です。
・業務ロジックは処理結果を返すべき
・関数は一値のみを返すべき
つまり赤間先生の「業務エラーは返り値で返す」という案には、「じゃあ処理結果は何で返すの」と反論したいわけです。
outパラメータで返す、や処理結果と業務エラーの二値を返す関数にする、などがありますが、あまりスマートには感じられません。
2008.06.04 00:51 URL | null #- [ 編集 ]
こんばんわ
> つまり赤間先生の「業務エラーは返り値で返す」という案には、「じゃあ処理結果は何で返すの」と反論したいわけです。
>
> outパラメータで返す、や処理結果と業務エラーの二値を返す関数にする、などがありますが、あまりスマートには感じられません。
赤間本では具体的な実装例が載っていませんでしたが、それらの方法以外思いつかないですね。
まぁ、元々戻り値が void のメソッドなら戻り値をそのまま使えますが・・・。
2008.06.04 02:23 URL | よこけん #Ay6tTHf6 [ 編集 ]
メソッドが業務エラーを
例外で返すのなら,
そのことを示す属性を付けておいてほしい。
outパラメータはスマートでないというが,
リソースが絡んでくるときは,
outパラメータでないと泣きを見ますよ。
2008.09.28 14:09 URL | アンテッ子 #bvNV3Ffs [ 編集 ]
> そのことを示す属性を付けておいてほしい。
属性を付けるということは何らかの処理を付加するということだと思うのですが、その辺りを詳しく聴かせて頂きたく思います。
そうではなく単なる目印として付けるということなら、XML コメントで充分、というか XML コメントを使うべきと思いますがいかがでしょう。
> リソースが絡んでくるときは,
すみません、リソースってのは何を指しているのでしょうか?
リソースというと、まず↓が思い浮かびますが、業務エラーの話とどう結びつくのかよくわからなかったです
http://msdn.microsoft.com/ja-jp/library/7k989cfy.aspx
2008.09.28 18:10 URL | よこけん #Ay6tTHf6 [ 編集 ]
自分も「業務エラーは例外で返す」に一票です。
例外という便利な機構を使わない理由がわかりません。C#に欠陥があるなら別ですが・・。
で・・。自作 Exception の使い方の一つを考えました。
Windows フォームアプリケーションで 自作 Exception の場合は、専用のメッセージエラー・ダイアログを出す例です。
-------------------------------- Program.cs ----------------------------
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
namespace MyApp {
class MyException : Exception {
public MyException(string msg) : base(msg) {}
}
static class Program {
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main() {
Application.ThreadException += Application_ThreadException; // <-- 追加
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) {
if (e.Exception is MyException)
MessageBox.Show(e.Exception.Message);
else
using (ThreadExceptionDialog dlg = new ThreadExceptionDialog(e.Exception)) {
if(dlg.ShowDialog() == DialogResult.Abort)
Application.Exit();
}
}
}
}
-------------------------------- Program.cs ----------------------------
すみません。コメント欄に綺麗にソースコードを張り付けるには、どうしたらいいですか・・?
実体参照で、インデントを空けました。ありがとうございます。
2008.10.14 19:46 URL | ica2500 #wLMIWoss [ 編集 ]
ica2500 さん、コメントありがとうございます。
試したことないので何とも言えませんが、ソースコードのインデントを保持しての貼り付けは無理かもしれません。
ソースコードのインデントを保持しての貼り付けは、全角スペースを使ったり、実体参照 (&nbsp;と半角で入力) を使用したりでいけますね。
2008.10.14 20:13 URL | よこけん #Ay6tTHf6 [ 編集 ]
>> ica2500 さん
実はその方法は昔やったことがあるのですが、今はその方法にはどちらかというと否定的な考えを持ってます。
まず、記事中にも書いてありますが、ユーザーに対して表示するエラーメッセージを Exception.Message に格納するのはあまり良くないです。
なぜなら、ユーザーに表示するためのメッセージは User Interface レイヤで扱うべきだからです。(例えば、画面の背景色をビジネスロジックが直接操作しているようなものです。)
これにより、自作例外共通の基底クラスを用意してそれをグローバルなエラーハンドラで処理するという方法は自然と取れなくなります。
ユーザーに表示するエラーメッセージを例外が持たないと言うことは、例外の発生した状況や例外の型に応じて適切なエラーメッセージを表示するように制御しなければならなくなるからです。
他にも、メッセージボックスではなくラベルにエラー表示する場合はグローバルなエラーハンドラが使えません。
ということで、グローバルなエラーハンドラは、予期せぬエラーを拾って通知するという目的でのみ使用するのが良いと思います。
# 「予期せぬエラー=仕様で対応していない異常系やバグ」ですので、メッセージボックスしか使えなくても別に良いと考えます。
トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/99-cfbefe59
久々に業務エラーについて
以前業務エラーについての記事を書いてから、もう 1 年半以上が経ちます。今でもこの記事にコメントを頂くことがあり大変有難いのですが、実...
2008.10.15 00:28 | C#と諸々