100

アサーションをいつどのように使用するかについて、たくさんの記事(およびStackOverflowに投稿された他のいくつかの同様の質問)を読み、それらをよく理解しました。Debug.Assertしかし、それでも、単純な例外をスローする代わりに、どのような動機が私を使用するように駆り立てるべきかはわかりません。つまり、.NETでは、失敗したアサーションに対するデフォルトの応答は、「ワールドを停止」してユーザーにメッセージボックスを表示することです。この種の動作は変更できますが、それを行うのは非常に面倒で冗長であることがわかります。代わりに、適切な例外をスローすることもできます。このようにして、例外をスローする直前にアプリケーションのログにエラーを簡単に書き込むことができます。さらに、アプリケーションが必ずしもフリーズするわけではありません。

Debug.Assertでは、単純な例外の代わりに使用する必要があるのはなぜですか?あるべきではない場所にアサーションを配置すると、あらゆる種類の「望ましくない動作」が発生する可能性があるため、私の観点では、例外をスローする代わりにアサーションを使用しても実際には何も得られません。あなたは私に同意しますか、それとも私はここで何かが欠けていますか?

注:「理論上」の違い(デバッグとリリース、使用パターンなど)は完全に理解していますが、私が見ているように、アサートを実行するのではなく、例外をスローする方がよいでしょう。プロダクションリリースでバグが発見された場合でも、「アサーション」を失敗させたいので(結局のところ、「オーバーヘッド」は途方もなく小さい)、代わりに例外をスローする方がよいでしょう。


編集:私が見ているように、アサーションが失敗した場合、それはアプリケーションがある種の破損した予期しない状態に入ったことを意味します。では、なぜ実行を継続したいのでしょうか。アプリケーションがデバッグバージョンで実行されているかリリースバージョンで実行されているかは関係ありません。同じことが両方に当てはまります

4

8 に答える 8

187

私はあなたの推論がもっともらしいことに同意します-つまり、アサーションが予期せず違反された場合、スローすることによって実行を停止することは理にかなっています-私は個人的にアサーションの代わりに例外を使用しません。理由は次のとおりです。

他の人が言っているように、アサーションは不可能な状況を文書化する必要があります。そのような方法で、不可能とされる状況が発生した場合に、開発者に通知されます。対照的に、例外は、例外的な、ありそうもない、または誤った状況に対して制御フローメカニズムを提供しますが、不可能な状況に対しては提供しません。私にとって、主な違いは次のとおりです。

  • 与えられたthrowステートメントを実行するテストケースを作成することは常に可能であるはずです。このようなテストケースを作成できない場合は、プログラムに実行されないコードパスがあり、デッドコードとして削除する必要があります。

  • アサーションを起動させるテストケースを作成することは決して不可能であるべきです。アサーションが発生した場合は、コードが間違っているか、アサーションが間違っています。いずれにせよ、コード内で何かを変更する必要があります。

そのため、アサーションを例外に置き換えません。アサーションが実際に起動できない場合は、それを例外に置き換えると、プログラムにテスト不可能なコードパスがあることを意味します。テストできないコードパスが嫌いです。

于 2009-09-23T20:39:49.257 に答える
18

アサーションは、プログラマーの世界に対する理解を確認するために使用されます。アサーションは、プログラマーが何か間違ったことをした場合にのみ失敗するはずです。たとえば、ユーザー入力をチェックするためにアサーションを使用しないでください。

「起こり得ない」状態のテストをアサートします。例外は、「発生してはならないが発生する」条件の場合です。

アサーションは、ビルド時(または実行時)に動作を変更できるため便利です。たとえば、リリースビルドでは、不要なオーバーヘッドが発生するため、アサートもチェックされないことがよくあります。これも注意が必要です。テストが実行されない場合もあります。

アサートの代わりに例外を使用すると、いくつかの値が失われます。

  1. 例外のテストとスローは少なくとも2行であるのに対し、assertは1行しかないため、コードはより冗長になります。

  2. テストとスローのコードは常に実行されますが、アサートはコンパイルできます。

  3. アサートはチェックしてスローする製品コードとは異なる意味を持つため、他の開発者とのコミュニケーションが失われます。プログラミングアサーションを実際にテストしている場合は、アサーションを使用してください。

詳細はこちら: http: //nedbatchelder.com/text/assert.html

于 2009-09-23T17:51:03.607 に答える
12

編集: あなたがあなたの投稿で行った編集/メモに応えて:あなたが達成しようとしていることのタイプのためにアサーションを使用するよりも例外を使用することが正しいことのように思えます。あなたが直面している精神的な障害は、同じ目的を達成するために例外とアサーションを検討していることだと思います。したがって、どちらを使用するのが「正しい」かを理解しようとしています。アサーションと例外の使用方法にはいくつかの重複があるかもしれませんが、同じ問題に対する異なる解決策であると混同しないでください。そうではありません。アサーションと例外には、それぞれ独自の目的、長所、短所があります。

私は自分の言葉で答えをタイプするつもりでしたが、これは私が持っているよりも概念をより良い正義にします:

C#ステーション:アサーション

assertステートメントを使用すると、実行時にプログラムロジックエラーをキャッチする効果的な方法になりますが、本番コードから簡単に除外できます。開発が完了すると、コンパイル中にプリプロセッサシンボルNDEBUG [すべてのアサーションを無効にする]を定義するだけで、コーディングエラーに対するこれらの冗長なテストの実行時コストを削減できます。ただし、本番バージョンでは、assert自体に配置されたコードが省略されることに注意してください。

アサーションは、次のすべてが成立する場合にのみ条件をテストするために最適に使用されます。

* the condition should never be false if the code is correct,
* the condition is not so trivial so as to obviously be always true, and
* the condition is in some sense internal to a body of software.

ソフトウェアの通常の動作中に発生する状況を検出するためにアサーションを使用することはほとんどありません。 たとえば、通常、アサーションを使用してユーザーの入力のエラーをチェックすることはできません。ただし、アサーションを使用して、呼び出し元がユーザーの入力をすでにチェックしていることを確認することは理にかなっています。

基本的に、本番アプリケーションでキャッチ/処理する必要があるものには例外を使用し、アサーションを使用して、開発には役立つが本番環境ではオフにする論理チェックを実行します。

于 2009-09-23T17:52:31.933 に答える
9

(考案された)実際的な例が違いを明らかにするのに役立つと思います:

MoreLinqのBatch拡張機能から採用)

// 'public facing' method
public int DoSomething(List<string> stuff, object doohickey, int limit) {

    // validate user input and report problems externally with exceptions

    if(stuff == null) throw new ArgumentNullException("stuff");
    if(doohickey == null) throw new ArgumentNullException("doohickey");
    if(limit <= 0) throw new ArgumentOutOfRangeException("limit", limit, "Should be > 0");

    return DoSomethingImpl(stuff, doohickey, limit);
}

// 'developer only' method
private static int DoSomethingImpl(List<string> stuff, object doohickey, int limit) {

    // validate input that should only come from other programming methods
    // which we have control over (e.g. we already validated user input in
    // the calling method above), so anything using this method shouldn't
    // need to report problems externally, and compilation mode can remove
    // this "unnecessary" check from production

    Debug.Assert(stuff != null);
    Debug.Assert(doohickey != null);
    Debug.Assert(limit > 0);

    /* now do the actual work... */
}

したがって、Eric Lippert et alが言ったように、あなた(開発者)が誤って他の場所で間違って使用した場合に備えて、正しいと期待するものだけを主張するので、コードを修正できます。基本的に、ユーザー入力など、何が入ってくるかを制御できないか予測できない場合に例外をスローします。これにより、不正なデータを与えたものはすべて適切に応答できます(ユーザーなど)。

于 2015-06-11T18:11:23.020 に答える
4

コードコンプリートからの別のナゲット:

「アサーションは、仮定が真でない場合に大声で文句を言う関数またはマクロです。アサーションを使用して、コードで行われた仮定を文書化し、予期しない条件を洗い流します。...

「開発中、アサーションは矛盾する仮定、予期しない条件、ルーチンに渡された悪い値などを洗い流します。」

彼はさらに、主張すべきものと主張すべきでないものに関するいくつかのガイドラインを追加します。

一方、例外:

「例外処理を使用して、予期しないケースに注意を向けます。例外ケースは、開発中に明らかになり、本番コードの実行時に回復できるように処理する必要があります。」

この本を持っていないなら、あなたはそれを買うべきです。

于 2009-09-23T17:58:29.107 に答える
1

Debug.Assertはデフォルトでデバッグビルドでのみ機能するため、リリースビルドで予期しない不正な動作をキャッチする場合は、例外を使用するか、プロジェクトプロパティでデバッグ定数をオンにする必要があります(一般的には良い考えではありません)。

于 2009-09-23T17:54:46.883 に答える
0

可能であるが発生してはならないことに対してアサーションを使用します(不可能な場合、なぜアサーションを配置するのですか?)。

それは使用する場合のように聞こえませんExceptionか?なぜアサーションの代わりにアサーションを使用するのExceptionですか?

アサーションのパラメータがfalseになるのを防ぐ、アサーションの前に呼び出されるコードがあるはずだからです。

Exception通常、スローされないことを保証するコードは前にありません。

Debug.Assert()製品にまとめられているのはなぜ良いのですか?デバッグで知りたいのなら、prodで知りたくないですか?

状況を見つけたら、それが二度と起こらないことDebug.Assert(false)を保証するコードを書くので、開発中にのみそれが必要です。Debug.Assert(false)開発が完了したら、Debug.Assert(false)状況を見つけて修正したと仮定すると、Debug.Assert()冗長になっているため、を安全にコンパイルできます。

于 2018-05-01T05:37:22.603 に答える
0

あなたがかなり大規模なチームのメンバーであり、クラスの重複を含め、すべて同じ一般的なコードベースで作業している人が何人かいるとします。他のいくつかのメソッドによって呼び出されるメソッドを作成することができます。ロックの競合を回避するために、別のロックを追加するのではなく、特定のロックを使用して呼び出し元のメソッドによって以前にロックされたと「想定」します。たとえば、Debug.Assert(RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld); 他の開発者は、呼び出し元のメソッドがロックを使用する必要があるというコメントを見落とす可能性がありますが、これを無視することはできません。

于 2018-12-03T17:39:24.503 に答える