142


35

ファローアップ:

NETの無効または予期しないパラメータに対してどのような種類の例外をスローする必要がありますか? いつ他のものを選ぶのでしょうか。

月に対応する整数を期待する関数があり、 '42’を渡した場合、どの例外を使用しますか? コレクションではありませんが、これは「範囲外」のカテゴリに分類されますか。

7 Answer


220


使用したいのは、 + ArgumentException ++ ArgumentNullException +、および `+ ArgumentOutOfRangeException +`です。

引数自体にあまり焦点を当てないで、呼び出し全体を判断するという選択肢もあります。

そのトリックは、そのメソッドがそのように呼ばれることができない理由を最もよく表す例外を投げることです。 理想的には、例外は何が悪かったのか、なぜそれが間違っているのか、そしてどのようにそれを修正するのかについて詳述されるべきです。

エラーメッセージがヘルプ、ドキュメンテーション、または他のリソースを指すときに私は大好きです。 例えば、マイクロソフトは彼らのナレッジベース記事で良い最初の一歩を踏み出しました。 http://support.microsoft.com/kb/927917 [Internet ExplorerでWebページにアクセスしたときに "Operation aborted"エラーメッセージが表示されるのはなぜですか。 エラーが発生すると、エラーメッセージのKB記事を参照します。 彼らがうまくいかないのは、彼らがあなたに話さないということです、なぜそれは特に失敗しました。

^〜コメントをくれたSTW(ex Yoooder)に感謝します。〜^

'' '' '

あなたのフォローアップに応じて、http://msdn.microsoft.com/en-us/library/system.argumentoutofrangeexception(loband).aspx [+ ArgumentOutOfRangeException +]をスローします。 MSDNがこの例外について言っていることを見てください。

_ メソッドが呼び出され、メソッドに渡された引数の少なくとも1つがnull参照(Visual Basicでは + Nothing +)でなく、有効な値が含まれていない場合、 `+ ArgumentOutOfRangeException +`がスローされます。 _

したがって、この場合は値を渡していますが、範囲は1から12なので、これは有効な値ではありません。 しかし、それを文書化する方法によって、APIが何を投げ出すかが明確になります。 私は `+ ArgumentOutOfRangeException `と言うかもしれませんが、別の開発者は ` ArgumentException +`と言うかもしれません。 それを容易にし、そして行動を文書化しなさい。


38


引数が有効であるが、オブジェクトが引数を使用すべきでない状態にある場合はSystem.InvalidOperationExceptionがスローされます。

更新 MSDNからの抜粋:

_ InvalidOperationExceptionは、メソッドの呼び出しの失敗が無効な引数以外の理由で発生した場合に使用されます。 _

オブジェクトにPerformAction(enmSomeActionアクション)メソッドがあり、有効なenmSomeActionsはOpenとCloseであるとしましょう。 PerformAction(enmSomeAction.Open)を続けて2回呼び出すと、2回目の呼び出しでInvalidOperationExceptionがスローされます(引数は有効だったため、コントロールの現在の状態に対しては無効になりました)。

あなたはすでに防御的にプログラミングによって正しいことをしているので、私が言及するもう一つの例外がありますObjectDisposedException。 あなたのオブジェクトがIDisposableを実装している場合、あなたは常に破棄された状態を追跡するクラス変数を持つべきです。オブジェクトが破棄されてメソッドが呼び出された場合はObjectDisposedExceptionを送出します。

public void SomeMethod()
{
    If (m_Disposed) {
          throw new ObjectDisposedException("Object has been disposed")
     }
    // ... Normal execution code
}

*更新:*あなたのフォローアップに答えるには:多少あいまいな状況にあり、特定のデータセットを表すために使用されている一般的な(.NET Genericsの意味ではない)データタイプによってもう少し複雑になります。 ;列挙型や他の強く型付けされたオブジェクトはより理想的なフィットです - しかし我々は常にそのコントロールを持っていません。

私は個人的にArgumentOutOfRangeExceptionに傾いて、有効な値が1〜12であることを示すメッセージを提供します。 私の考えは、月について話すとき、月の整数表現がすべて有効であると仮定すると、1から12の範囲の値を期待しているということです。 特定の月(31日の月など)のみが有効であれば、それ自体Rangeを扱わず、有効な値を示す一般的なArgumentExceptionをスローし、それらをメソッドのコメントにも記録します。


35


実際の値とどの例外が最適かによって異なります。

これが十分に正確でない場合は、 `+ ArgumentException +`から独自の例外クラスを派生させてください。

Yoooderの答えは私を啓発しました。 入力がいつでも無効であれば* invalid 、入力がシステムの現在の状態に対して無効であれば unexpected *です。 したがって、後者の場合、http://msdn.microsoft.com/en-us/library/system.invalidoperationexception(VS.80、loband).aspx [+ InvalidOperationException +]が妥当な選択です。


4


http://msdn.microsoft.com/en-us/library/system.argumentexception(VS.71).aspx[引数の例外]
  • System.ArgumentException

  • System.ArgumentNullException

  • System.ArgumentOutOfRangeException


3


_ ArgumentExceptionは、メソッドが呼び出され、渡された引数の少なくとも1つが呼び出されたメソッドのパラメーター仕様を満たさない場合にスローされます。 ArgumentExceptionのすべてのインスタンスは、無効な引数とその引数に想定される値の範囲を説明する意味のあるエラーメッセージを伝える必要があります。 _

特定の種類の無効性については、いくつかのサブクラスも存在します。 このリンクには、サブタイプの概要と適用時期が記載されています。


2


*短い答え:*どちらもない

*長い答え:*引数の使用*例外(コンポーネントライブラリなど、その上にある製品であるライブラリを除く)は匂いです。 例外は、バグではなく、ユーザーではなく、例外的な状況を処理することです。 APIコンシューマの)不足

*最長の答え:*ライブラリを書かない限り、無効な引数に対する例外を投げるのは失礼です。 私は2つ(またはそれ以上)の理由で、アサーションを使用することを好みます。

  • アサーションをテストする必要はありませんが、throwアサーションはテストしますが、ArgumentNullExceptionに対するテストはばかげています(試してみてください)。

  • アサーションはユニットの意図された使用法をよりよく伝え、そしてクラスの振る舞い仕様よりも実行可能なドキュメンテーションに近い。

  • アサーション違反の動作を変更できます。 例えば、デバッグコンパイルではメッセージボックスは問題ありませんので、QAはすぐにそれにぶつかるでしょう(それが起こったところでIDEが壊れるかもしれません)、一方ユニットテストではアサーション失敗をテスト失敗として示すことができます。

null例外の処理は次のようになります(明らかに皮肉なことです)。

{library.Method(null);を試してください。 } catch(ArgumentNullException e){//今回は実引数で再試行します。library.Method(realArgument); }

例外は、状況が予想されるが例外的な場合に使用されるものとします(IOの失敗など、消費者の管理の及ばないことが起こります)。 引数*例外はバグの指標であり、(私の考えでは)テストで処理され、Debug.Assertで支援されるものとします。

ところで:この特定のケースでは、intの代わりにMonth型を使用することができます。 C#は型の安全性に関しては不十分ですが(アスペクト#rulez!)、時にはあなたはそれらのバグをまとめて防ぐ(あるいはコンパイル時に捕らえる)ことができます。

そして、はい、MicroSoftはそれについては間違っています。


0


標準のArgumentExceptionを使用することも、サブクラス化して独自に作成することもできます。 いくつかの特定のArgumentExceptionクラスがあります。

どちらが最もうまくいくか