try {…} が最終的に {…} に適しているのはなぜですか。{…}キャッチ{}してみてはいかがでしょうか?

StackOverflow https://stackoverflow.com/questions/128818

質問

特にその 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 以降のコードは実行されません)。

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

役に立ちましたか?

解決

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

他のヒント

「最後に」は、「プログラムの状態が正常であることを確認するために常に実行しなければならないこと」のステートメントです。したがって、例外がプログラムの状態を狂わせる可能性がある場合には、これを使用するのが常に良い方法です。コンパイラはまた、Finally コードが確実に実行されるようにするために多大な労力を費やします。

「キャッチ」は「この例外から回復できる」という宣言です。本当に修正できる例外からのみ回復する必要があります。引数なしで catch すると、「何でも回復できます!」となりますが、これはほとんどの場合真実ではありません。

もし すべての例外から回復することが可能だった場合、それは実際に、意図を宣言しているものについての意味論的な屁理屈になるでしょう。しかし、そうではなく、ほぼ間違いなく、あなたのフレームより上のフレームには、特定の例外を処理するための機能が備わっているでしょう。そのため、finally を使用すると、クリーンアップ コードを無料で実行できますが、より知識のあるハンドラーに問題を処理してもらいます。

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

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

2 番目のブロックでは例外が発生します。 投げられた そして泡が立つ しかしreader.Close() まだ実行することが保証されています。

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

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

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

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

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

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

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

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

最後にブロックは特別です。CLR は、finally ブロック内のコードを catch ブロックとは別に認識して扱います。CLR は、finally ブロックが常に実行されることを保証するために多大な労力を費やします。それはコンパイラからの単なる構文糖ではありません。

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

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

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

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

try..finally ブロックは、発生した例外をスローします。全て finally これは、例外がスローされる前にクリーンアップ コードが実行されることを保証します。

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

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

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

メソッドが例外を処理する方法を知らないが、例外が発生した後にクリーンアップが必要な場合は、次を使用します。 Try..Finally

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

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

どの例外タイプをキャッチするか、またはそれをどう処理するかがわからない場合は、catch ステートメントを用意する意味がありません。状況についてより詳しい情報を持っている上層部の発信者に、何をすべきかを知らせるためにそのままにしておいてください。

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

読みやすさの観点からは、将来のコードリーダーに「ここにあるこのようなものが重要であり、何が起こっても行う必要がある」とより明示的に伝えています。これはいい。

また、空の catch ステートメントには、ある種の「臭い」が付く傾向があります。これらは、開発者が、発生する可能性のあるさまざまな例外とその処理方法をよく考えていないことの表れである可能性があります。

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

引用元: ここ

例外の発生とキャッチは、メソッドの正常な実行の一部として日常的に発生するべきではありません。クラス ライブラリを開発する場合、例外が発生する可能性のある操作を実行する前に、クライアント コードにエラー条件をテストする機会を与える必要があります。たとえば、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 を参照)。例外スロー手法のパフォーマンスへの影響には、例外の割り当て、スロー、キャッチのコストと、その後の例外オブジェクトのガベージ コレクションのコストが含まれます。つまり、例外スローの瞬間的な影響はそれほど高くありません。より多くの例外がスローされると、頻繁なガベージ コレクションが問題になるため、例外をスローするコーディング手法を頻繁に使用することによる全体的な影響はテスト 8.05 と同様になります。

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

読んでいただければ プログラマーのための C# Final ブロッ​​クはアプリケーションを最適化し、メモリ リークを防ぐために設計されたことが理解できるでしょう。

CLR では漏れを完全になくすことはできません...プログラムが不要なオブジェクトへの参照を誤って保持すると、メモリ リークが発生する可能性があります

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

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

そして、この 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();
}

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

まず、処理する必要のない例外をキャッチするのは悪い習慣です。チェックアウト 第 5 章 .Net パフォーマンスについて から .NET アプリケーションのパフォーマンスとスケーラビリティの向上. 。余談ですが、おそらく try ブロック内でストリームをロードする必要があります。こうすることで、失敗した場合に関連する例外をキャッチできます。try ブロックの外側でストリームを作成すると、その目的が無効になります。

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

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

Try/finally ブロックを使用すると、高速に失敗しながらクリーンアップ コードを実行できます。ほとんどの状況では、すべての例外をグローバル レベルでキャッチして、ログに記録して終了できるようにする必要があります。

例外がスローされない限り、例間の実質的な違いは無視できます。

ただし、「try」句内で例外がスローされた場合、最初の例は例外を完全に飲み込みます。2 番目の例では、呼び出しスタックの次のステップに例外を発生させます。そのため、記載されている例の違いは、1 つは例外を完全に隠している (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 インスタンスを閉じて破棄します。お役に立てれば。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top