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


163

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

ファローアップ:

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

回答:


249

:私が使用したいArgumentExceptionArgumentNullExceptionArgumentOutOfRangeException

議論自体にそれほど焦点を当てず、むしろ全体として呼びかけを判断する他のオプションもあります:

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

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

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

コメントをありがとうSTW(元Yoooder)に再び。


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

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

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


PSST!あなたが彼の具体的な質問に正確に回答したことに同意しますが、防御的なコーディングと検証パラメーターをまとめるのに役立つ以下の私の回答をご覧ください;-D
STW

+1ですが、スローされる例外とその理由を文書化することは、「正しい」例外を選択することよりも重要です。
pipTheGeek 2009

@pipTheGeek-私はそれが本当に議論の余地があるポイントだと思います。文書化は間違いなく重要ですが、消費する開発者が積極的または防御的であり、実際に文書を詳細に読むことも期待しています。エンドユーザーにはどちらか一方だけが表示され、もう一方は表示されない可能性があるため、優れたドキュメントよりもわかりやすい/説明的なエラーを選択します。全文を読む貧しいプログラマーよりも、エンドユーザーが貧弱なプログラマーに記述エラーを伝える可能性が高い
STW

4
ArgumentExceptionをキャッチすると、ArgumentOutOfRangeもキャッチされることに注意してください。
Steven Evers

方法FormatException:引数の形式が無効である場合、または複合形式文字列の形式が正しくない場合にスローされる例外。
アンソニー

44

ジョシュの回答に投票しましたが、リストにもう1つ追加したいと思います。

引数は有効ですが、オブジェクトが引数を使用してはならない状態の場合、System.InvalidOperationExceptionがスローされます。

MSDNから取得した更新

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

オブジェクトにPerformAction(enmSomeAction action)メソッドがあり、有効なenmSomeActionsがOpenおよびCloseであるとします。連続して2回PerformAction(enmSomeAction.Open)を呼び出すと、2番目の呼び出しでInvalidOperationExceptionがスローされます(arugmentは有効でしたが、コントロールの現在の状態ではないため)。

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

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

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

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


1
いい視点ね。これにより、無効な入力と検査されていない入力の違いが説明される場合があります。+1
ダニエル・ブリュックナー

ああ、私はあなたが雷を盗むつもりはなかったとあなたに同意します。しかし、あなたがそれを指摘したので、私は私の答えを更新しました
JoshBerke 2009

38

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

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

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


6
InvalidOperationExceptionに関するMSDNのページからの引用:「InvalidOperationExceptionは、メソッドの呼び出しの失敗が無効な引数以外の理由で発生した場合に使用されます。」
STW


3

ArgumentException

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

特定のタイプの無効性のために、いくつかのサブクラスも存在します。リンクには、サブタイプの概要とそれらがいつ適用されるかが示されています。


1

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

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

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

  • アサーションはテストする必要はありませんが、スローアサーションはテストする必要があり、ArgumentNullExceptionに対するテストはばかげています(試してみてください)。
  • アサーションは、ユニットの使用目的をより適切に伝え、クラスの動作仕様よりも実行可能なドキュメントに近いものです。
  • アサーション違反の動作を変更できます。たとえば、デバッグコンパイルではメッセージボックスは問題ないので、QAはすぐにメッセージボックスにヒットします(また、IDEが発生した行で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タイプを使用できます。C#はタイプセーフティ(Aspect#rulez!)に関しては不十分ですが、これらのバグをすべて一緒に防止(またはコンパイル時にキャッチ)することができます。

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


6
私見、呼び出されたメソッドが合理的に進むことができない場合、例外もスローされるべきです。これには、呼び出し元が偽の引数を渡した場合も含まれます。代わりに何をしますか?-1を返しますか?
ジョンサンダース

1
無効な引数によって内部関数が失敗する場合、内部関数からInvalidArgumentExceptionをキャッチしてより詳細なものでラップするのではなく、引数の有効性をテストすることの長所と短所は何ですか?後者のアプローチは、一般的なケースではパフォーマンスを向上させるように思われますが、あまり効果が見られませんでした。
スーパーキャット2018年

この質問をグーグルですばやく検索すると、一般的な例外をスローすることがすべての最悪の慣行であることがわかります。主張の主張に関しては、小さな個人プロジェクトではメリットがあると思いますが、無効な引数がアプリケーションの設定不良または理解不足が原因である可能性が最も高いエンタープライズアプリケーションではそうではありません。
最大

0

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

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

どちらが最もよく機能します。


1
私はほとんどすべてのケースに同意しません。提供される.NET Argument * Exceptionクラスは非常に一般的に使用され、問題をコンシューマーに通知するために十分な特定の情報を提供する機能を提供します。
STW

明確にするために-Argument * Exceptionクラスから派生するほとんどすべてのケースに同意しません。.NET引数例外の1つに加えて説明的で明確なメッセージを使用すると、引数が無効であるあらゆる状況に十分な詳細が提供されます。
STW

同意しましたが、利用可能なオプションについて説明しました。私は間違いなく「推奨」方法についてもっと明確にすべきでした。
スコットM.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.