204

引数なしでcatchを使用するのは悪い形式であると人々が言うのを見たことがあります。特に、そのcatchが何もしない場合はそうです。

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

ただし、これは適切な形式と見なされます。

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

私が知る限り、finallyブロックにクリーンアップコードを配置することと、try..catchブロックの後にクリーンアップコードを配置することの唯一の違いは、tryブロックにreturnステートメントがあるかどうかです(この場合、finallyのクリーンアップコードは実行しますが、try..catchの後のコードは実行しません)。

そうでなければ、最終的に何がそんなに特別なのですか?

4

20 に答える 20

365

大きな違いはtry...catch、エラーが発生したという事実を隠して、例外を飲み込むことです。try..finallyクリーンアップコードを実行すると、例外が発生し続け、それをどう処理するかを知っている何かによって処理されます。

于 2008-09-24T18:12:51.533 に答える
63

「最後に」は、「プログラムの状態が正常であることを確認するために常に実行しなければならないこと」のステートメントです。そのため、例外によってプログラムの状態が失われる可能性がある場合は、常に1つ用意することをお勧めします。コンパイラーはまた、Finallyコードが確実に実行されるように細心の注意を払っています。

「Catch」は「この例外から回復できます」というステートメントです。本当に修正できる例外からのみ回復する必要があります。引数なしでキャッチすると、「ねえ、私は何からでも回復できます!」と表示されますが、これはほとんどの場合正しくありません。

すべての例外から回復することが可能であるとすれば、それは、あなたが意図していることを宣言していることについて、実際には意味論的な疑問になります。ただし、そうではなく、ほぼ確実に、特定の例外を処理するために、フレームの上のフレームがより適切に装備されます。そのため、最後に使用して、クリーンアップコードを無料で実行しますが、それでも、より知識のあるハンドラーが問題に対処できるようにします。

于 2008-09-24T18:12:34.950 に答える
33

その 1 行で例外がスローされると、それがわからないからです。

コードの最初のブロックでは、例外は単純に吸収され、プログラムの状態が間違っている可能性がある場合でも、プログラムは実行を続けます。

2 番目のブロックでは、例外がスローされてバブルが発生しますがreader.Close()それでも実行が保証されます。

例外が予期されていない場合は、try..catch ブロックを配置しないでください。後でプログラムが悪い状態になり、その理由がわからない場合にデバッグするのが難しくなります。

于 2008-09-24T18:14:23.900 に答える
21

何があっても最後に実行されます。したがって、tryブロックが成功した場合は実行され、tryブロックが失敗した場合は、catchブロックが実行され、次にfinallyブロックが実行されます。

また、次の構成を使用してみることをお勧めします。

using (StreamReader reader=new  StreamReader("myfile.txt"))
{
}

usingステートメントはtry/finallyで自動的にラップされ、ストリームは自動的に閉じられます。(実際に例外をキャッチしたい場合は、usingステートメントの周りにtry / catchを配置する必要があります)。

于 2008-09-24T18:14:50.907 に答える
7

次の 2 つのコード ブロックは同等ですが、等しくありません。

try
{
  int i = 1/0; 
}
catch
{
  reader.Close();
  throw;
}

try
{
  int i = 1/0;
}
finally
{
  reader.Close();
}
  1. 「最終的に」は意図を明らかにするコードです。このコードは何があっても実行する必要があることをコンパイラや他のプログラマに宣言します。
  2. 複数の catch ブロックがあり、クリーンアップ コードがある場合は、finally が必要です。Final がなければ、各 catch ブロックでクリーンアップ コードを複製することになります。(DRY原則)

finally ブロックは特別です。CLR は、finally ブロックを含むコードを catch ブロックとは別に認識して処理します。CLR は、finally ブロックが常に実行されることを保証するために多大な努力を払います。これは、コンパイラからの構文糖衣だけではありません。

于 2008-09-24T20:55:21.970 に答える
5

Try..Catch..Finallyメソッドが例外をローカルで処理する方法を知っている場合は、を使用します。Try で例外が発生し、Catch で処理され、その後、Finally でクリーンアップが行われます。

メソッドが例外の処理方法を認識していないが、例外が発生したらクリーンアップが必要な場合は、使用しますTry..Finally

これにより、例外は呼び出し元のメソッドに伝達され、呼び出し元のメソッドに適切な Catch ステートメントがある場合は処理されます。現在のメソッドまたは呼び出し元のメソッドのいずれにも例外ハンドラーがない場合、アプリケーションはクラッシュします。

これによりTry..Finally、呼び出し元のメソッドに例外を伝播する前に、ローカルのクリーンアップが確実に行われます。

于 2016-09-20T05:56:32.500 に答える
5

ここでのコンセンサスと思われることに同意します-空の「キャッチ」は、tryブロックで発生した可能性のある例外をマスクするため、悪いです。

また、読みやすさの観点から、「try」ブロックが表示されると、対応する「catch」ステートメントがあると思います。「finally」ブロックでリソースの割り当てが解除されるようにするために「try」のみを使用している場合は、代わりに「using」ステートメントを検討してください。

using (StreamReader reader = new StreamReader('myfile.txt'))
{
    // do stuff here
} // reader.dispose() is called automatically

'using' ステートメントは、IDisposable を実装する任意のオブジェクトで使用できます。オブジェクトの dispose() メソッドは、ブロックの最後で自動的に呼び出されます。

于 2008-09-24T18:28:06.740 に答える
3

try..finallyブロックは、発生した例外をスローします。例外finallyがスローされる前にクリーンアップコードが実行されるようにするだけです。

空のcatchを指定したtry..catchは、例外を完全に消費し、それが発生したという事実を隠します。リーダーは閉じられますが、正しいことが起こったかどうかはわかりません。iをファイルに書き込むことが目的だった場合はどうなりますか?この場合、コードのその部分に到達せず、myfile.txtは空になります。すべてのダウンストリームメソッドはこれを適切に処理しますか?空のファイルを見ると、例外がスローされたために空であると正しく推測できますか?例外をスローして、何か間違ったことをしていることを知らせたほうがよいでしょう。

もう1つの理由は、このように行われたtry..catchが完全に正しくないことです。こうすることであなたが言っているのは、「何が起こっても、私はそれを処理できる」ということです。どうですかStackOverflowException、その後片付けてもらえますか?どうOutOfMemoryExceptionですか?一般に、予期し、処理方法を知っている例外のみを処理する必要があります。

于 2008-09-24T18:16:01.010 に答える
2

最後はオプションです。クリーンアップするリソースがない場合、「Finally」ブロックを設定する理由はありません。

于 2008-09-24T18:14:39.597 に答える
2

から取られた:ここ

メソッドの正常な実行の一部として、例外の発生とキャッチが日常的に発生することはありません。クラスライブラリを開発するときは、例外が発生する可能性のある操作を実行する前に、クライアントコードにエラー状態をテストする機会を与える必要があります。たとえば、System.IO.FileStreamは、Readメソッドを呼び出す前にチェックできるCanReadプロパティを提供し、次のコードスニペットに示すように、潜在的な例外が発生するのを防ぎます。

Dim str As Stream = GetStream()If(str.CanRead)Then'ストリームを読み取るコードEndIf

例外を発生させる可能性のある特定のメソッドを呼び出す前にオブジェクトの状態をチェックするかどうかの決定は、オブジェクトの予想される状態によって異なります。FileStreamオブジェクトが、存在する必要のあるファイルパスと、読み取りモードでファイルを返す必要のあるコンストラクターを使用して作成されている場合、CanReadプロパティを確認する必要はありません。FileStreamを読み取れない場合は、行われたメソッド呼び出しの予想される動作に違反するため、例外を発生させる必要があります。対照的に、メソッドが読み取り可能または読み取り不可能なFileStream参照を返すものとして文書化されている場合は、データの読み取りを試みる前にCanReadプロパティを確認することをお勧めします。

「例外まで実行」コーディング手法を使用するとパフォーマンスに与える影響を説明するために、キャストが失敗した場合にInvalidCastExceptionをスローするキャストのパフォーマンスを、キャストが失敗した場合にnullを返すC#as演算子と比較します。2つの手法のパフォーマンスは、キャストが有効な場合(テスト8.05を参照)でも同じですが、キャストが無効で、キャストを使用すると例外が発生する場合、キャストを使用すると、キャストを使用するよりも600倍遅くなります。オペレーターとして(テスト8.06を参照)。例外スロー手法の高性能への影響には、例外の割り当て、スロー、およびキャッチのコストと、その後の例外オブジェクトのガベージコレクションのコストが含まれます。つまり、例外のスローによる瞬間的な影響はそれほど高くありません。より多くの例外がスローされると、

于 2008-09-24T18:14:42.823 に答える
2

キャッチする例外の種類やその処理方法がわからない場合は、catch ステートメントを使用しても意味がありません。何をすべきかを知るために、状況についてより多くの情報を持っている可能性のある上層部の発信者に任せてください.

その例外が呼び出し元にスローされる前にリソースをクリーンアップできるように、例外が発生した場合に備えて、まだそこに finally ステートメントが必要です。

于 2008-09-24T18:13:20.737 に答える
2

可読性の観点から、将来のコードリーダーに「ここにあるものは重要であり、何が起こっても実行する必要がある」ことをより明確に伝えています。これはいい。

また、空の catch ステートメントには、特定の「匂い」がする傾向があります。これは、発生する可能性のあるさまざまな例外とその処理方法について、開発者が考えていないことを示している可能性があります。

于 2008-09-24T18:14:15.993 に答える
2

例外を再スローするためだけに catch 節を追加するのは悪い習慣です。

于 2012-09-27T12:48:15.527 に答える
2

プログラマー向けの C# を読めば、finally ブロックがアプリケーションを最適化し、メモリ リークを防ぐための設計であることを理解できるでしょう。

CLR はリークを完全に排除するわけではありません...プログラムが不注意に不要なオブジェクトへの参照を保持すると、メモリリークが発生する可能性があります

たとえば、ファイルまたはデータベース接続を開くと、マシンはそのトランザクションに対応するためにメモリを割り当てます。そのメモリは、破棄または閉じるコマンドが実行されない限り保持されません。try.. finally..ただし、トランザクション中にエラーが発生した場合、ブロック内にない限り、進行中のコマンドは終了しません。

catchfinallycatch は、エラー自体を処理/管理または解釈する方法を提供するための設計であるという意味で、それとは異なりました。それは、「悪者を捕まえたぞ。彼らに何をしてほしい?」と言う人のことだと考えてください。whilefinallyは、リソースが適切に配置されていることを確認するように設計されています。悪者がいようとなかろうと、あなたの財産がまだ安全であることを確認してくれる誰かのことを考えてみてください。

そして、あなたはそれら2つが永久に一緒に働くことを許可する必要があります.

例えば:

try
{
  StreamReader reader=new  StreamReader("myfile.txt");
  //do other stuff
}
catch(Exception ex){
 // Create log, or show notification
 generic.Createlog("Error", ex.message);
}
finally   // Will execute despite any exception
{
  reader.Close();
}
于 2016-04-29T10:33:10.840 に答える
1

一つには、わざわざ処理しない例外をキャッチするのは悪い習慣です。.NETアプリケーションのパフォーマンスとスケーラビリティの向上による.Netパフォーマンスについての第5章を確認してください。ちなみに、おそらくtryブロック内にストリームをロードする必要があります。そうすれば、失敗した場合に適切な例外をキャッチできます。tryブロックの外側にストリームを作成すると、その目的が無効になります。

于 2008-09-24T18:18:17.713 に答える
1

finally を使用すると、catch ステートメントが呼び出し元のプログラムに例外をスローした場合でも、リソースをクリーンアップできます。空の catch ステートメントを含む例では、ほとんど違いはありません。ただし、キャッチで何らかの処理を行ってエラーをスローした場合、またはキャッチがまったくない場合でも、finally は引き続き実行されます。

于 2008-09-24T18:14:18.473 に答える
0

おそらく多くの理由の中で、例外の実行は非常に遅いです。これが頻繁に発生する場合は、実行時間を簡単に損なう可能性があります。

于 2008-09-24T18:14:41.390 に答える
0

すべての例外をキャッチするtry/catchブロックの問題は、不明な例外が発生した場合にプログラムが不確定な状態になることです。これは、フェイルファストルールに完全に反します。例外が発生した場合にプログラムを続行したくない場合です。上記のtry/catchはOutOfMemoryExceptionsもキャッチしますが、それは間違いなくプログラムが実行されない状態です。

try / finalブロックを使用すると、高速で失敗しながらクリーンアップコードを実行できます。ほとんどの場合、すべての例外をグローバルレベルでキャッチするだけで、ログに記録してから終了できます。

于 2008-09-24T18:14:48.940 に答える
0

例外がスローされない限り、例間の効果的な違いはごくわずかです。

ただし、'try' 節で例外がスローされた場合、最初の例は例外を完全に飲み込みます。2 番目の例は、コール スタックの次のステップに例外を発生させます。そのため、記載されている例の違いは、1 つは例外を完全に覆い隠し (最初の例)、もう 1 つは (2 番目の例) 例外情報を保持して後で処理する可能性があることです。 「finally」句のコンテンツをまだ実行しています。

たとえば、例外をスローした最初の例の「catch」句にコードを配置した場合 (最初に発生したもの、または新しいもの)、リーダーのクリーンアップ コードは実行されません。'catch' 句で何が起こるかに関係なく、最終的に実行されます。

したがって、「catch」と「finally」の主な違いは、「finally」ブロックの内容は (いくつかのまれな例外を除いて)予期しない例外に直面した場合でも実行が保証されていると見なすことができるということです。 'catch' 句 (ただし、'finally' 句の外) には、そのような保証はありません。

ちなみに、Stream と StreamReader はどちらも IDisposable を実装しており、'using' ブロックでラップできます。「Using」ブロックは、try/finally (「catch」なし) と意味的に同等であるため、例は次のように簡潔に表現できます。

using (StreamReader reader = new  StreamReader("myfile.txt"))
{
  int i = 5 / 0;
}

...これにより、StreamReader インスタンスがスコープ外になると閉じて破棄されます。お役に立てれば。

于 2008-09-24T18:28:06.240 に答える
0

try {…} catch{} は必ずしも悪いわけではありません。これは一般的なパターンではありませんが、スレッドの最後で (おそらく) 開いているソケットを閉じるなど、何があってもリソースをシャットダウンする必要がある場合に使用する傾向があります。

于 2008-09-24T22:26:20.223 に答える