8

作業しているオブジェクトに、それに関連付けられている他のオブジェクトのコレクションがあるとします。たとえば、WinFormのControlsコレクションです。コレクション内の特定のオブジェクトをチェックしたいのですが、コレクションにContains()メソッドがありません。これに対処するにはいくつかの方法があります。

  • Contains()コレクション内のすべてのアイテムをループして、それらの1つが探しているものであるかどうかを確認することにより、独自のメソッドを実装します。これは「ベストプラクティス」のアプローチのようです。
  • 私は最近、ループの代わりに、次のようにtryステートメント内のオブジェクトにアクセスしようとしたコードに出くわしました。
try  
{  
    Object aObject = myCollection[myObject];  
}  
catch(Exception e)  
{  
    //if this is thrown, then the object doesn't exist in the collection
}

私の質問は、プログラミングの実践がどれほど貧弱であると思いますか、そしてその理由は何ですか?コレクションのループと比較して、パフォーマンスはどうですか?

4

8 に答える 8

4

一般的な経験則では、例外をトリガーする状況が「例外的」でない限り、制御フローに例外を使用しないようにします。たとえば、非常にまれです。

これが正常かつ定期的に発生するものである場合は、例外として処理しないでください。

例外は、関連するすべてのオーバーヘッドのために非常に非常に遅いため、十分な頻度で発生している場合は、パフォーマンス上の理由も考えられます。

于 2008-08-12T00:30:43.390 に答える
3

これはかなり悪い習慣だと言わざるを得ません。コレクションをループすることは例外をスローするのに効率が悪いと言う人もいるかもしれませんが、例外をスローすることにはオーバーヘッドがあります。また、辞書やハッシュテーブルの使用に適しているのに、コレクションを使用してキーでアイテムにアクセスしている理由についても疑問があります。

ただし、このコードに関する私の主な問題は、スローされた例外のタイプに関係なく、常に同じ結果が残ることです。

たとえば、オブジェクトがコレクションに存在しないため、コレクション自体がnullであるため、またはmyCollect [myObject]をaObjectにキャストできないために、例外がスローされる可能性があります。

これらの例外はすべて同じ方法で処理されますが、これは意図したものではない可能性があります。

これらは、例外をスローすることが通常許容できると考えられる時期と場所に関する2つの優れた記事です。

私は2番目の記事からのこの引用が特に好きです:

メソッドが通常の機能を完了できないような予期しないアクティビティまたは無効なアクティビティが発生した場合にのみ、例外がスローされることが重要です。例外処理はオーバーヘッドが小さく、パフォーマンスが低下するため、条件付き処理の代わりに通常のプログラムフローに使用しないでください。このように例外処理を誤用するコードを維持することも難しい場合があります。

于 2008-08-12T00:26:37.577 に答える
0

コードの記述中にこのオブジェクトがコレクションに含まれていることを期待し、実行時にそうではないことがわかった場合、それを例外ケースと呼びます。例外を使用するのが適切です。

ただし、単にオブジェクトの存在をテストしていて、オブジェクトが存在しないことがわかった場合、これは例外ではありません。この場合に例外を使用することは適切ではありません。

実行時のパフォーマンスの分析は、使用されている実際のコレクションと、それを検索する場合の方法によって異なります。しかし、それは問題ではありません。最適化の錯覚に惑わされて、紛らわしいコードを書いてはいけません。

于 2008-08-12T00:01:59.110 に答える
0

私はそれがどれだけ好きかについてもっと考えなければならないでしょう...私の本能は、ええと、それほどではありません...

編集:例外的なケースに関するライアン・フォックスのコメントは完璧です、私は同意します

パフォーマンスに関しては、コレクションのインデクサーに依存します。C#ではインデクサー演算子をオーバーライドできるため、containsメソッドのようにforループを実行している場合は、同じように遅くなります(try / catchのために数ナノ秒遅くなる可能性があります...しかし、そのコード自体が巨大なループ内にない限り、心配してください)。

インデクサーがO(1)(またはO(log(n))...またはO(n)よりも速いもの)の場合、もちろん、try/catchソリューションの方が高速です。

また、インデクサーが例外をスローしていると想定しています。nullを返している場合は、もちろんnullをチェックするだけで、try/catchを使用しないでください。

于 2008-08-12T00:07:06.027 に答える
0

一般に、プログラムフローとロジックに例外処理を使用することは悪い習慣です。私は個人的に、後者のオプションは例外の許容できない使用であると感じています。最近一般的に使用されている言語の機能(たとえば、C#のLinqやラムダなど)を考えると、独自のContains()メソッドを作成しない理由はありません。

最後に、最近のほとんどのコレクションには、すでにcontainsメソッドがあります。ですから、ほとんどの場合、これは問題ではないと思います。

于 2008-08-12T00:10:19.297 に答える
0

例外は例外的である必要があります。

「データベースが下から落ちたため、コレクションが欠落しています」のようなものは例外的です

「キーが存在しない」のようなものは、辞書の通常の動作です。

winforms Controlコレクションの特定の例では、ControlsプロパティにContainsKeyメソッドがあります。これは、使用することになっているものです。

ContainsValue辞書/ハッシュテーブルを扱う場合、コレクション全体を反復処理して、何かが存在するかどうかを確認する以外に方法がないため、そうすることは本当にお勧めできません。

例外が例外である理由については、2つのことについてです

  1. コードが実行しようとしていることを示します。コードを読みやすく、保守しやすいように、コードが達成しようとしているものとできるだけ一致させたいと考えています。例外処理は、この目的の邪魔になる余分な問題の束を追加します

  2. コードの簡潔さ。あなたはあなたのコードが最も直接的な方法でそれがしていることをすることを望みます、それでそれは読みやすくそして維持可能です。繰り返しになりますが、例外処理によって追加された問題はこれを妨げます。

于 2008-08-12T02:02:49.723 に答える
0

Krzystof の次のブログ投稿をご覧ください: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

例外は、エラー状態の伝達に使用する必要がありますが、制御ロジックとしては使用しないでください (特に、Contains など、条件を判断するためのはるかに単純な方法がある場合)。

問題の一部は、スローするのにコストがかからない例外をキャッチするのにコストがかかり、すべての例外がある時点でキャッチされることです。

于 2008-08-17T14:38:19.963 に答える
-2

後者は許容できる解決策です。その場合、コレクションがスローする特定の例外(ElementNotFound?)を確実にキャッチしますが。

速度的には、一般的なケースによって異なります。要素が見つからない可能性が高い場合は、例外ソリューションの方が高速です。失敗する可能性が高い場合は、コレクションのサイズとその反復速度によって異なります。いずれにせよ、このような速度を心配する前に、これが実際にボトルネックであるかどうかを確認するために、通常の使用に対して測定する必要があります。最初に明確にするために行ってください、そして後者の解決策は前者よりはるかに明確です。

于 2008-08-12T00:03:04.957 に答える