なぜこれらの例外をスローしないのですか?


111

私はこのMSDNページに出くわしました:

独自のソースコードから意図的にExceptionSystemExceptionNullReferenceException、またはIndexOutOfRangeExceptionをスローしないでください

残念ながら、その理由を説明することはありません。理由は推測できますが、この件についてより権威のある誰かが洞察を提供してくれることを願っています。

最初の2つは明らかな意味を持っていますが、後の2つはあなたが採用したいもののように見えます(実際、私はそうです)。

さらに、これらは回避すべき唯一の例外ですか?他に人がいる場合、それらは何であり、なぜそれらも回避する必要があるのですか?


22
msdn.microsoft.com/en-us/library/ms182338.aspxから:ライブラリまたはフレームワークでExceptionやSystemExceptionなどの一般的な例外タイプをスローすると、ユーザーが実行する不明な例外を含め、すべての例外をキャッチします。処理方法がわかりません。
Henrik、

3
なぜNullReferenceExceptionをスローするのですか?
Rik

5
@Rik:NullArgumentException一部の人々が両方を混同する可能性があるのと似ています。
Moslem Ben Dhaou 2014年

2
@Rik拡張メソッド、私の回答による
マークグラベル

3
あなたが投げてはいけないもう一つはApplicationException
マシューワトソン14年

回答:


98

Exceptionはすべての例外の基本型であり、そのため非常に不特定です。この例外は、有用な情報が含まれていないだけなので、スローしないでください。例外をキャッチするコードを呼び出しても、意図的にスローされた例外(ロジックから)を、まったく望ましくない他のシステム例外から明確にし、実際の障害を指摘することはできませんでした。

同じ理由がにも当てはまりますSystemException。派生型のリストを見ると、非常に異なるセマンティクスを持つ他の多数の例外を確認できます。

NullReferenceExceptionIndexOutOfRangeExceptionは違う種類のものです。現在、これらは非常に特殊な例外であるため、スローしても問題ありません。ただし、これらは通常、ロジックに実際の誤りがあることを意味するため、これらをスローする必要はありません。たとえば、null参照例外は、であるオブジェクトのメンバーにアクセスしようとしていることを意味しますnull。それがコードで可能性がある場合は、常に明示的にチェックしnullて、より有用な例外をスローする必要があります(たとえばArgumentNullException)。同様に、IndexOutOfRangeExceptionsは(リストではなく配列の)無効なインデックスにアクセスすると発生します。あなたはいつも最初にそれをしないことを常に確認しそして例えば配列の境界を最初にチェックすべきです。

例えば、これらの2、のようないくつかの他の例外がありますInvalidCastExceptionDivideByZeroExceptionあなたのコード内の特定の障害のためにスローされ、通常、あなたが何かを間違ってやっているか、あなたが最初のいくつかの無効な値をチェックされていないことを意味しています。コードから故意にそれらをスローすることにより、呼び出し側のコードが、コード内の何らかの障害が原因でスローされたかどうか、または実装で何かに再利用することにしたかどうかを判断するのが難しくなります。

もちろん、これらの規則にはいくつかの例外があります(笑)。既存のものと完全に一致する例外を引き起こす可能性があるものを構築している場合は、特にいくつかの組み込み動作を一致させようとしている場合は、それを自由に使用してください。非常に具体的な例外タイプを選択することを確認してください。

ただし、一般的に、ニーズを満たす(特定の)例外を見つけない限り、特定の予期される例外に対して独自の例外タイプを作成することを常に検討する必要があります。特にライブラリコードを記述している場合、例外ソースを分離するのに非常に役立ちます。


3
第三部は私にはほとんど意味がありません。確かに、これらのエラーを最初から引き起こさないようにする必要がありますが、たとえばIList実装を作成する場合、要求されたインデックスに影響を与えるのはあなたの力ではなく、インデックスが無効な場合の呼び出し元のロジックの間違いであり、通知することができます適切な例外をスローすることにより、この論理エラーを回避します。なぜIndexOutOfRangeException適切ではないのですか?

7
@delnanを実装している場合は、インターフェースのドキュメントにIList示さArgumentOutOfRangeExceptionれているように、aがスローされますIndexOutOfRangeException配列用であり、私の知る限り、配列を再実装することはできません。
2014年

2
多少関連している可能性もありますNullReferenceExceptionが、通常は内部的にAccessViolationException(IIRCテストはのような特殊なケースとしてスローされcmp [addr], addrます。つまり、ポインターを逆参照しようとし、アクセス違反で失敗した場合、NREとAVEの違いを処理します。結果の割り込みハンドラで)。したがって、意味上の理由とは別に、不正行為もいくつかあります。それが役に立たないnullときに手動でチェックするのをやめさせるのにも役立つかもしれません-とにかくNREをスローするつもりなら、なぜ.NETにやらせないのですか?
Luaan 14年

あなたの最後の声明に関して、カスタム例外について:私はこれを行う必要性を感じたことがありません。おそらく私は何かを逃している。フレームワークから何かを作成する代わりに、どのような状況でカスタム例外タイプを作成する必要がありますか?
DonBoitnott 2014年

1
まあ、小さなアプリケーションでは必要ないかもしれません。しかし、個々のパーツが独立した「コンポーネント」として機能する、より複雑なものを作成するとすぐに、カスタムエラー状況に対してカスタム例外を導入することが理にかなっています。たとえば、アクセス制御層があり、権限がないにもかかわらずサービスを実行しようとすると、カスタムの「アクセス拒否例外」などがスローされる可能性があります。または、ファイルを解析するパーサーがある場合、ユーザーに報告する独自のパーサーエラーがある可能性があります。
2014年

36

最後の2つの意図は、予期された意味を持つ組み込みの例外との混同を防ぐことであると私は思います。ただし、例外の意図をそのまま保持している場合は、それが正しいと私は思いますthrow。たとえば、カスタムコレクションを作成している場合、使用することは完全に合理的であるように見えますIndexOutOfRangeException。IMOよりも明確で具体的ですArgumentOutOfRangeException。そしてList<T>後者を選択するかもしれませんが、BCL(配列は含まない)には少なくとも 41か所(リフレクターの礼儀)があり、特注をスローしますIndexOutOfRangeException-特別な免除に値するのに十分な「低レベル」はありません。ええ、私はあなたがそのガイドラインがばかげていると正当に主張できると思います。同様に、NullReferenceException 拡張メソッドで少し便利です-セマンティクスを保持したい場合:

obj.SomeMethod(); // this is actually an extension method

スローNullReferenceExceptionする場合objですnull


2
「例外の正確な意図を保持している場合」-確かにそうだった場合、最初にテストすることなく例外がスローされますか?そして、すでにテスト済みの場合、それは本当に例外ではありませんか?
PugFugly 2014年

5
@PugFuglyは、拡張メソッドの例を見るのに2秒かかります。いいえ、それをテストする必要がない限り、それはスローされません。SomeMethod()メンバーアクセスを実行する必要がない場合、強制的に実行するのは正しくありません。同様に、カスタムを作成するBCLの41の場所とカスタムを作成IndexOutOfRangeExceptionする16の場所でそのポイントを取り上げますNullReferenceException
マークグラベル

16
拡張メソッドはまだのArgumentNullException代わりにをスローするべきだと私は主張しNullReferenceExceptionます。拡張メソッドからの構文糖は、通常のメンバーアクセスと同じ構文を許可しても、それでも非常に異なる動作をします。そして、NREを取得するのはMyStaticHelpers.SomeMethod(obj)間違っています。
2014年

1
@PugFugly BCLは「基本クラスライブラリ」であり、基本的に.NETの中核となるものです。
2014年

1
@PugFugly:条件を事前に検出できないと、「不便な」ときに例外がスローされるシナリオが多数あります。操作が成功しない場合は、操作を開始して途中まで進み、結果として生じた部分的に処理された混乱をクリーンアップする必要があるよりも、例外を早くスローする方が適切です。
スーパーキャット2014年

5

ご指摘のとおり、「例外をスローするときに回避System.IndexOutOfRangeExceptionすべきものというトピックの記事「例外の作成とスロー(C#プログラミングガイド)」で、Microsoftは実際に独自のソースコードから意図的にスローされるべきではない例外タイプとしてリストしています。

ただし、対照的に、スロー(C#リファレンス)の記事では、Microsoftは独自のガイドラインに違反しているようです。Microsoftがその例に組み込んだメソッドは次のとおりです。

static int GetNumber(int index)
{
    int[] nums = { 300, 600, 900 };
    if (index > nums.Length)
    {
        throw new IndexOutOfRangeException();
    }
    return nums[index];
}

したがって、Microsoft自体のIndexOutOfRangeExceptionドキュメントでは、throw

これにより、少なくともの場合、プログラマによってIndexOutOfRangeExceptionその例外タイプスローされ、許容できるプラクティスと見なされる場合があると私は信じるようになりました。


1

私はあなたの質問を読んだとき、どのような条件で例外タイプをスローしたいのかNullReferenceExceptionInvalidCastExceptionまたはを自分に問いかけましたArgumentOutOfRangeException

私の意見では、これらの例外タイプの1つに遭遇したとき、コンパイラーが私に話しているという意味で、私(開発者)は警告に不安を感じています。したがって、あなた(開発者)がそのような例外タイプをスローできるようにすることは、(コンパイラー)が責任を販売することと同じです。たとえば、これはコンパイラがオブジェクトがであるかどうかを開発者が決定できるようにする必要があることを示唆していますnull。しかし、そのような決定を下すことは、コンパイラの仕事であるべきです。

PS:2003年以来、私は自分の例外を開発してきました。そうすることがベストプラクティスと考えられています。


良い点。ただし、プログラマは.NET Frameworkランタイムにこれらの種類の例外をスローさせる(そして、プログラマはそれらを適切に処理する必要がある)と言う方が正確だと思います。
DavidRR 2014

0

NullReferenceExceptionとについての議論をIndexOutOfBoundsException置く:

キャッチとスローについてはどうですかSystem.Exception。私は自分のコードでこのタイプの例外を何度も投げてきましたが、それによって騙されたことは一度もありません。同様に、非常に頻繁に不特定のExceptionタイプをキャッチし、それも私にとってはかなりうまくいきました。それで、なぜですか?

通常、ユーザーは、エラーの原因を区別できる必要があると主張します。私の経験から、さまざまな例外タイプを異なる方法で処理する必要がある状況はごくわずかです。ユーザーがプログラムでエラーを処理することが予想される場合は、より具体的な例外タイプをスローする必要があります。その他の場合については、一般的なベストプラクティスガイドラインに確信が持てません。

だから、投げるExceptionということについては、これをすべての場合に禁止する理由はわかりません。

編集:MSDNページからも:

例外を使用して、通常の実行の一部としてプログラムのフローを変更しないでください。例外は、エラー状態の報告と処理にのみ使用してください。

さまざまな例外タイプの個別のロジックでcatch句をやりすぎることも、ベストプラクティスではありません。


例外メッセージは、何が起こったかを示すためにまだ残っています。消費者がそれらのエラーをプログラムで区別したい場合に備えて、さまざまなエラーごとに新しい例外タイプを作成することは想像できません。
上部

以前のコメントはどうなりましたか?
DonBoitnott
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.