web-dev-qa-db-ja.com

.NETで無効または予期しないパラメーターに対してスローされる例外は何ですか?

.NETで無効または予期しないパラメーターに対してスローされる例外のタイプは何ですか?別の代わりに1つを選択するのはいつですか?

ファローアップ:

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

152
Even Mien

使用したいのは、ArgumentExceptionArgumentNullException、およびArgumentOutOfRangeExceptionです。

引数自体にはあまり焦点を当てず、呼び出し全体を判断する他のオプションもあります。

  • InvalidOperationException –引数は問題ないかもしれませんが、オブジェクトの現在の状態ではありません。 クレジットはSTW(以前はYoooder)に送られます。投票 彼の答え 同様に。
  • NotSupportedException –渡された引数は有効ですが、この実装ではサポートされていません。 FTPクライアントを想像して、クライアントがサポートしていないというコマンドを渡します。

秘Theは、メソッドをそのまま呼び出せない理由を最もよく表す例外をスローすることです。理想的には、例外は何が間違っていたのか、なぜ間違っているのか、どのように修正するのかについて詳しく説明する必要があります。

エラーメッセージがヘルプ、ドキュメント、またはその他のリソースを指しているのが大好きです。たとえば、MicrosoftはKB記事で最初の一歩を踏み出しました。 「Internet ExplorerでWebページにアクセスすると、「操作が中止されました」というエラーメッセージが表示されるのはなぜですか?」 。エラーが発生すると、エラーメッセージのKB記事を参照します。彼らがうまくいかないのは、彼らがあなたに何も具体的にそれが失敗した理由を教えないということです。

コメントをくれたSTW(元Yoooder)に再び感謝します。


あなたのフォローアップに応じて、 ArgumentOutOfRangeException をスローします。この例外についてMSDNが言っていることを見てください。

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

したがって、この場合、値を渡しますが、範囲は1〜12であるため、それは有効な値ではありません。ただし、文書化する方法により、APIがスローする内容が明確になります。私はArgumentOutOfRangeExceptionと言うかもしれませんが、別の開発者はArgumentExceptionと言うかもしれません。簡単にし、動作を文書化します。

236
JoshBerke

Josh's answer に投票しましたが、もう1つリストに追加したいと思います。

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

更新MSDNから取得:

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

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

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

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

更新:あなたのフォローアップに答えるには:少しあいまいな状況であり、ジェネリック( .NET Generics sense)特定のデータセットを表すために使用されるデータ型。列挙型またはその他の強く型付けされたオブジェクトは、より理想的なフィットになりますが、常にその制御ができるとは限りません。

私は個人的にArgumentOutOfRangeExceptionに傾倒し、有効な値が1〜12であることを示すメッセージを提供します。私の推論は、すべての月の整数表現が有効であると仮定して、あなたが月について話すとき、あなたは1-12の範囲の値を期待しているということです。特定の月(31日間の月など)のみが有効な場合、範囲ごとに処理することはできず、有効な値を示す一般的なArgumentExceptionをスローし、メソッドのコメントにもそれらを文書化します。

42
STW

実際の値と最適な例外に応じて:

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

Yoooderの答えは私を啓発しました。入力はいつでも有効でない場合はinvalidであり、入力はunexpectedシステムの現在の状態に対して有効でない場合。したがって、後者の場合、 InvalidOperationException が妥当な選択です。

35

引数の例外

  • System.ArgumentException
  • System.ArgumentNullException
  • System.ArgumentOutOfRangeException
4
Syed Tayyab Ali

ArgumentException

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

特定の種類の無効化のためのサブクラスもいくつかあります。リンクには、サブタイプの概要と、それらを適用するタイミングがあります。

3
Ben S

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

長い回答:
Argument * Exceptionを使用することは(コンポーネントライブラリなどの製品であるライブラリを除く)においです。例外は、バグではなく例外的な状況を処理することであり、ユーザー(つまりAPIコンシューマー)の不足ではありません。

最長回答:
ライブラリを作成しない限り、無効な引数に対して例外をスローするのは失礼です。
次の2つ(またはそれ以上)の理由から、アサーションの使用を好みます。

  • アサーションはテストする必要はありませんが、スローアサーションはテストする必要があり、ArgumentNullExceptionに対するテストはとんでもないように見えます(試してみてください)。
  • アサーションは、ユニットの使用目的をよりよく伝え、クラスの動作仕様よりも実行可能なドキュメントに近くなります。
  • アサーション違反の動作を変更できます。たとえば、デバッグコンパイルではメッセージボックスに問題はありません。そのため、QAですぐにヒットします(IDEが発生した行で中断します)。ユニットテストでは、テストの失敗としてのアサーションの失敗。

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

try {
    library.Method(null);
}
catch (ArgumentNullException e) {
    // retry with real argument this time
    library.Method(realArgument);
}

例外は、状況が予想されるが例外的である場合に使用されます(IO障害など、消費者の制御の及ばない事態が発生します)。 Argument * Exceptionはバグを示すものであり、(私の意見では)テストで処理され、Debug.Assertで支援されます。

ところで:この特定のケースでは、intの代わりにMonthタイプを使用できます。タイプセーフティ(Aspect#rulez!)に関してはC#は不足しますが、これらのバグをまとめて防止(またはコンパイル時にキャッチ)できる場合があります。

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

1
THX-1138

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

http://msdn.Microsoft.com/en-us/library/system.argumentexception(VS.71).aspx

どちらが最適に機能します。

0
Scott M.