17

驚いたことに、私はこの主題について SO に関する以前の質問を 1 つしか見つけることができませんでした。私のアプローチについて、コミュニティの「信任投票」(またはそうでない!) を取得したいと思います。

私がそれを見る方法は次のとおりです。

  • Debug.Assertあなたが期待することが真実であることを述べるために使用します。これは、環境を完全に制御している場合に使用されます。たとえば、事前条件と事後条件を検証する方法です。
  • 例外的な状況が発生した場合は例外を使用します。ファイル、データベース、ネットワークなどの外部リソースを扱うのは簡単です。しかし...

次のシナリオでは、少し曖昧になります。これは説明のみを目的とした不自然な例であることに注意してください。

パブリック プロパティ MyMode と method を持つクラス MyClass があるとしますGetSomeValueForCurrentMode()。MyClass は、他の開発者が使用するライブラリで出荷 (リリース ビルド) されることを意図したものと考えてください。

MyMode は、このクラスの外部ユーザーによって更新されることを期待しています。現在、GetSomeValueForCurrentMode()次のロジックがあります。

switch(MyMode)
{
case Mode.ModeA:
return val1;
case Mode.ModeB:
return val2;
default:
//Uh-uh this should never happen

}

ここで私が得ているのは、MyClass のユーザーがそれを無効な状態のままにしたということです。だから何をすべきか?

デフォルトでは、私たちDebug.Assertまたはthrow new InvalidOperationException(または他の)べきですか?

クラスのユーザーを信頼してはならないという 1 つのマントラがあります。Debug.Assert を選択し、MyClass をリリース ビルドとしてビルドした場合 (それによってデバッグ アサートを削除した場合)、クラスのユーザーは、クラスを無効な状態のままにしておいたという有用な情報を取得できません。しかし、それは、完全に制御できないことが起こった場合にのみ例外をスローするという別のマントラに反するものです。

私はこれについてぐるぐる回っていることに気づきました - 決定的な「正しい」答えがないように見えるプログラミングの議論の1つです。それでは投票に入れましょう!

編集:関連する SO の質問 (アサーションまたは例外を使用した契約による設計? ) でこの応答に気付きました:

経験則として、自分自身のエラーをキャッチしようとするときはアサーションを使用し、他の人のエラーをキャッチしようとするときは例外を使用する必要があります。つまり、例外を使用して、パブリック API 関数の前提条件を確認し、システムの外部にあるデータを取得するたびに確認する必要があります。システム内部の関数またはデータにはアサートを使用する必要があります。

私にとって、これは理にかなっており、以下に概説する「アサートしてからスローする」手法と組み合わせることができます。

考えを歓迎します!

4

8 に答える 8

5

私は基本的にあなた自身の質問の結論に同意します:シラミのコードがシラミが犯した間違いを検出した場合、それはA ssert場合です(そしてパフォーマンスが他に指示しない限り、アサーションはプロダクションコードに残されるべきです)。アリスのコードがイブのコードの誤りを検出した場合、アリスとイブがバグ追跡ソフトウェアの反対側にいると仮定すると、それはExceptions場合です

これが一般的な経験則です。わずかに変更された形式のアサーションは、 「ヘッズアップ、開発者」としても使用できます。メカニズム(そして、それらは「ASSERT」ではなく「HEADS_UP」または同様のものと呼ばれるべきです)。あなたの会社がクライアント/サーバー製品を開発していて、サーバーがクライアントに無効なデータを送信した場合はどうなりますか?クライアントプログラマーの場合は、それを外部データ(kaputtであるのはEveのデータ)として扱いたいと考えており、例外をスローしたいと考えています。ただし、Visual Studioのデバッガーをその場で停止させる「よりソフトな」アサーションは、これらの問題を非常に早期に検出してサーバーチームに報告するための非常に優れた方法です。実際のインストールでは、イブとアリスの間のデータでマロリーがテンパリングしている可能性がありますが、ほとんどの場合、それは同僚の1人によるバグであり、発生したときにそれを確認したいので、私はそれらを呼び出します「ヘッズアップ」アサーション:彼らはしません

于 2009-02-03T09:39:34.077 に答える
5

私はここにいるほとんどの人に同意し、Design-by-Contract に従います。デプロイされたコードの要件 (コントラクト) と、設計中に期待される状態を把握すること (デバッグ アサーション) を明確に区別する必要があります。

コントラクト アサーションは常に例外としてスローする必要があります (常に例外であるため)。ほとんどのフレームワークには、デバッグ アサーションをキャッチするメカニズムが組み込まれています。ただし、実行時には常に例外をスローする必要があります。

これを支援するためにカスタム ライブラリを使用します (C#/VB.NET)。これが実際にどのように機能するかに興味がある場合は、最近 Codeplex ( http://www.contractdriven.com/ )にアップしました。

これの副次的な利点は、DbC をより定期的に使用し始めると、コードに既に明示的な保証が書き込まれているため、デバッグ アサーションを使用する必要がほとんどないことです。そのため、実際には無効な状態になるのは困難です。

したがって、元の投稿の質問...「ここで私が得ているのは、MyClass のユーザーが無効な状態のままにしているということです。では、どうすればよいでしょうか?」...決して発生するべきではありません。

もう何もデバッグする必要はないかもしれません! ;-)

于 2009-02-03T10:33:48.663 に答える
5

まず、MyClass が有効であることは、もちろん MyClass のinvariantで表現する必要があります。

次に、「このクラスの外部ユーザーによって MyMode が更新されることを期待しています」と言います。

  void Setter(mode m)
  {
    // INVARIANT ASSERT (1)
    // PRECONDITION ASSERTS (uses "m") (2)

    // BODY (3)

    // POSTCONDITION ASSERTS (if any) (4)
    // INVARIANT ASSERT (5)
  }

(5) では、不変式が成り立たない絶叫アサーション違反で失敗します。しかし、(2) では、渡されたモード mが無効であるため、以前に失敗します。これにより、ユーザーに明確なメッセージが送信され、問題が解決されます。

また、mode フィールドが public であり、ユーザーが何の制御もなしにそれを変更するとは言わないでください。

編集:アサーションとリリースモードについては、以下も参照してください。

于 2009-02-03T08:20:31.350 に答える
4

多くの場合、両方: アサートしてからスローします。

開発中に誤った仮定を開発者に通知したいため、アサートします。

リリースビルドでこれが発生した場合、システムが悪い状態で処理を続行しないようにする必要があるため、スローします。

システムの望ましい信頼性特性がここでの選択に影響を与える可能性がありますが、「アサートしてからスローする」は多くの場合、有用な戦略だと思います。

于 2009-02-03T08:24:01.013 に答える
2

私の assert の使用は、契約による設計のアイデアに従います。基本的に、関数に入るときに受信パラメーター、グローバル変数、およびその他の状態情報が有効であることをアサートし、終了するときに戻り値と状態も有効であることをアサートします。最初に失敗したアサートが発生した場合、それは呼び出し元のコードのバグであり、最後に発生した場合、バグはこのコードにあります。これらは事前条件と事後条件です。

switch ステートメントでの assert は、エントリの前提条件を確認した場合にのみ本当に役立ちます。このシナリオで関数の途中で許容できない状態に到達した場合、それは関数または呼び出された関数での失敗です。個人的には、例外ではないので、ここで assert に固執します。おっしゃる通り、例外はバグではなくリソースに関連しています。ただし、リリース ビルドに存在し、失敗時に例外をスローするカスタム アサーション ハンドラーを作成して、プログラムが安定した状態に戻る機会を与えることができます。

于 2009-02-03T08:16:36.007 に答える
1

バグが他の誰かのコードにある場合、または別のサブシステムのコードにある場合 (自分が書いたかどうかに関係なく)、例外を使用してください。ファイルなどの外部ソースから取得したデータにエラーがある場合にも、例外を使用します。

データが外部ソースからのものかどうかわからない場合があります。セキュリティが重要であり、正しいことが検証されていない外部データを扱っている可能性がある場合は、例外を使用してください。セキュリティが重要でない場合は、タイブレーカーとしてパフォーマンスを使用します。このコードはタイトなループで実行される可能性がありますか? その場合は、リリース ビルドでパフォーマンスが向上するため、アサートの使用を検討してください。それ以外の場合は、例外を使用してください。

于 2009-11-06T19:06:45.940 に答える
0

言語によって異なりますが、構文シュガーを使用する場合は assert を使用する必要があります。ただし、Java アサートでは、これを機能させるためにオンにする必要があるため、例外の方が優れています。ただし、特定の例外がある方が常に良いため、ここでは IllegalStateException にする必要があります。

于 2009-02-03T08:11:35.157 に答える
0

.Net では、リリース ビルドを作成するときに Debug クラス メソッドがプログラムに含まれていないため、このコードが運用環境になると、例外をスローする必要があります。

于 2009-02-03T08:16:29.330 に答える