独自の例外を作成する必要がありますか、それともわずかに非標準的な目的で同様の例外を選択する必要がありますか?


8

これは一般的なデザインの質問ですが、私がC#と.NETに焦点を合わせています。これは、これらが現在使用している言語だからです。

独自の新しい例外クラスを作成する必要がありますか、それともわずかに異なる目的で既存のフレームワーク例外を選択する必要がありますか?

たとえば、メンバ(つまり、型など)が予期されていたが、を使用してアセンブリを読み取っているときに見つからなかったことを示す例外が必要であることがわかりましたMono.Cecil。基本クラスライブラリは例外を定義しますMissingMemberException。これは、私が欲しいものを正確に伝えているようですが、説明では次のように述べています。

存在しないクラスメンバーに動的にアクセスしようとした場合にスローされる例外。

メンバーに動的にアクセスするのではなく、アセンブリを受動的に操作するため、これは正確には適合しません。


必要なのは、名前ではなくタイプを再利用することです。MissingMemberExceptionには特定の意味があります。フレームワークに固有で正確に正しい意味を持つ新しいタイプを定義するだけです。
usr

回答:


7

一般に

例外をサブクラス化することは、例外をそれらが属するファミリーまたはグループにグループ化することをお勧めします。また、特定のエラーに基づいて、またはより一般的には、例外を処理する機会をクライアントコードに許可します。私は通常、ルートの近くのどこかでツリーを論理エラーと実行時エラーの間で分割します(C ++ではstd::runtime_errorvsなどstd::logic_error)。

システム例外とアプリケーションの例外を区別できることも良い考えです。クライアントコードが何らかのシステム障害を監視しているのに(基本クラスを介して)コードの論理エラーをキャッチするのは奇妙です。

このケースとC#を考える

C#には豊富で大きな例外階層があります。基本クラスを深く掘り下げようとはしません。あなたの例に従うと、論理エラー(または少なくともアプリケーションエラー)をスローしているように聞こえるので、基本クラスまたはその例外でさえ、システムエラーを示唆します。正確な例外については議論の余地がありますが、この場合は適切な選択ではないと思います。

階層

システムエラーとアプリケーションエラー、さらには実行時エラーと論理エラーを区別できる階層を構築します。内部例外を使用することを恐れないでください。システムエラーをキャッチし、スローされるコンテキストを考慮して、より意味のあるものにラップします。重要な例外となるものに焦点を合わせて、やり過ぎないでください。例外には、固有のテキストによる説明を関連付けることができます。例外を使用して、問題を修正するために何をすべきかについての詳細またはヒントをユーザーに提供します。


2
これは、例外をサブクラス化する際の優れた戦略です。すべてのケースで例外をサブクラス化するように言っているのか、それともサブクラス化するときにこれを行うべきかを単に言っているのかはわかりません。サブクラス化する必要があるかどうかに関しては、@ DanielSが投稿した回答に同意します。
チャックコンウェイ

3

答えはもちろん「依存する」ですが、あなたのユースケースを考えると、私はノーと言うでしょう。理由は次のとおりです。

C#はすばらしいです-それをスクラッチして、最高の-オブジェクト指向言語です。実際、とても良いので、単純なプロジェクトとして始まったものについて、狂信的に純粋なビジョンを実装しようとすることに巻き込まれることがあります。JavaScriptやObjective-CやPHPのコードを書くときは、そんなことはあまりありません。

私がこの「モード」、この種の麻痺に入るとき、症状の1つは例外処理とジェネリックとメタプログラミングへの執着かもしれません。3つすべてが一緒になることもあります。新しい、比較的未知の、または粗末な仕様と目標に取り組んでいる場合、問題になる可能性がはるかに高くなります。実装の詳細に行き詰まるのではなく、私が合理的に予想するほとんどのシナリオに対応できるものを作成しようとするのはなぜでしょうか。その後、詳細を取得するのに取り掛かると、基礎が築かれ、ずんぐりした小さなメソッドの束などが作成されます。たぶん他の誰かがUIコードで作業するでしょう、私はそれらにこれらの素晴らしいサービスとこれらの契約を提供します...

残念ながら、それはまだ私には起こりません。起こりがちなのは、私が「インフラストラクチャ」に取り組んでいるこの道から始めることです。

  • 独自のIoCコンテナーインターフェイスを作成するか、他の方法でねじ込む Castle.Windsor
  • アプリケーションでタイプマッピングを処理する方法を決定する
  • 例外処理を使用して、抽象メンバーへの呼び出しに類似しその呼び出しをラップする抽象基本クラスの制御フローロジックInterceptors を作成する
  • 以下のための抽象基底クラスを作成するIRepositoryIUnitOfWorkIDomainServiceICrossCuttingValidation、など
  • まさにそのようなIFrameworkExceptionメタアプローチを否定する何かのための階層的オブジェクトモデルを記述しようとすること(のような

例外の説明があなたの好みに十分正確であるかどうかに夢中になったら、他のいくつかの重要な機能が実装されていないことを本当に否定しています。例外の性質からもわかるように、これはイベント駆動型の例外ではなく、入力方法(UIやパイプなど)から明らかに遠く離れて発生し、おそらく本質的に決定論的です-のように、ユーザーが何を入力するかを予測しますが、どのアセンブリをロードするかなどを予測できます。

ちなみに、説明が気になるなら、適切なスコープでオーバーライドする拡張メソッドを書いてみませんか?

ですから、これは本当に私に一種の抽象化と分析麻痺をあなたに投影することですが、私はそれが適切だと思います。安全面にとどまるためには、次のException場合にのみサブクラス化します。

  • 一般的に処理しようとしているランタイム例外を実際に経験しました
  • ランタイム例外は、設計時に合理的に除外できるものではありません
  • 例外は、既存の膨大な数のExceptionサブクラスではまだ十分にカバーされていません
  • あなたは実際にあなたが例外をどのように処理したいのか、そうでない場合はそれを考えています、それはあなたがそれを考えてそれに戻る必要があるほど複雑だからです
  • あなたのアイデアは、メタデータ、そのスコープ、その内部例外などを変更するだけでなく、例外を生成する基になるオブジェクトまたはイベント、および/または実際にそれを処理する方法をより多く扱います
  • あなたはすでにUIを書いている、またはUIのようなものの入力に面する側の大部分に対して責任がない

私はあなたの実用的なアプローチに感謝します。すべてがそうであるように、それは依存します。
チャックコンウェイ

1

私の見解では、カスタム例外は2つの場合にのみ意味があります。

1)APIを開発している

2)コードでそれを使用して、障害から回復します。

その他のシナリオでは、組み込みの例外で十分です。

あなたの場合、あなたはInvalidArgumentExceptionを使うことができます


答えを少し広げて、各箇条書きに「なぜ」を与えるべきです。あなたはここにいる。カスタムの例外を作成することは、維持すべきもう1つのシステム/階層です。
チャックコンウェイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.