c# - pass - try catch std
なぜtry{...}が最終的に{...}良いですか。 try{...} catch{} bad? (14)
try {...} 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..finallyブロックは引き続き発生した例外をスローします。 finally
は、例外がスローされる前にクリーンアップコードが確実に実行されます。
try..catchを空のキャッチで使用すると、例外が完全に消費され、発生したという事実が隠されます。 読者は閉じますが、正しいことが起こったかどうかは分かりません。 あなたの意図が私がファイルに書き込むことだったら? この場合、コードのその部分には作成されず、 myfile.txtは空になります。 すべての下流の方法でこれが正しく処理されますか? 空のファイルが表示されたら、例外がスローされたため空であると正しく推測できますか? 例外をスローし、あなたが何か間違っていることが分かっているようにしてください。
別の理由は、try..catchが完全に間違っているように行われたことです。 これを行うことによってあなたが言っていることは、「何が起こっても、私はそれを処理することができます」です。 Exception
はどうですか?それ以降はクリーンアップできますか? OutOfMemoryException
どうですか? 一般的には、予想される例外処理方法のみを処理する必要があります。
プログラマのためにC#を読んでいるなら、finallyブロックはアプリケーションを最適化し、メモリリークを防ぐ設計であることを理解するでしょう。
CLRはリークを完全に排除しません...プログラムが不注意で不要なオブジェクトへの参照を誤って保持するとメモリリークが発生することがあります
たとえば、ファイルまたはデータベース接続を開くと、マシンはそのトランザクションを処理するためにメモリを割り当てます。廃棄されたコマンドまたは実行されなかったコマンドが実行されない限り、そのメモリは保持されません。 トランザクション中にエラーが発生した場合、 try.. finally..
ブロック内になければ処理を終了し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();
}
あなたの例の効果的な違いは、例外がスローされない限り無視してもかまいません。
ただし、 'try'句で例外がスローされた場合、最初の例は完全にそれを飲み込むでしょう。 2つ目の例では、コールスタックの次のステップへの例外が発生します。したがって、前述の例の違いは、例外が完全に隠蔽され(1つ目の例)、後で処理される可能性のある例外情報が保持される'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ブロックの問題は、未知の例外が発生した場合、プログラムが不定状態になってしまうことです。 これはフェイル・ファースト・ルールとは完全に逆行します。例外が発生した場合でもプログラムを続行しないようにします。 上記のtry / catchはOutOfMemoryExceptionsをキャッチしますが、それは間違いなくプログラムが実行されない状態です。
Try / finallyブロックを使用すると、クリーンアップコードを実行しても失敗することはありません。 ほとんどの場合、グローバルレベルですべての例外をキャッチし、ログに記録してから終了する必要があります。
なぜなら、その1行で例外がスローされると、あなたはそれを知ることができないからです。
コードの最初のブロックでは、例外は単に吸収されますが、プログラムの状態が間違っている場合でもプログラムは実行を継続します。
2番目のブロックでは、例外がスローされてバブルアップしますが 、 reader.Close()
は引き続き実行されます。
例外が予想されない場合は、try..catchブロックを置かないでください。後でプログラムが悪い状態になったときにデバッグするのが難しく、理由がわかりません。
キャッチする例外の種類やその処理の種類がわからない場合は、catchステートメントを使用する必要はありません。 あなたは何をすべきかを知るために状況についてのより多くの情報を持っているかもしれない上位の呼び出し者のためにそれを残すべきです。
例外がある場合にはfinallyステートメントをまだ持っていなければなりません。そのため、例外が呼び出し元にスローされる前にリソースをクリーンアップすることができます。
メソッドをローカルで処理する方法がわかっている場合は、 Try..Catch..Finally
使用します。 ExceptionはTryで処理され、Catchで処理され、その後Cleanで最後に行われます。
あなたのメソッドが例外の処理方法を知らないが、いったんそれが発生しTry..Finally
クリーンアップが必要な場合は、 Try..Finally
これにより、例外が呼び出しメソッドに伝播され、呼び出しメソッドに適切なCatchステートメントがある場合に処理されます。現在のメソッドまたは呼び出しメソッドのいずれかに例外ハンドラがない場合、アプリケーションがクラッシュします。
Try..Finally
てTry..Finally
に、呼び出し元のメソッドに例外を伝播する前に、ローカルでクリーンアップが行われていることを確認します。
大きな違いは、 try...catch
はエラーを発生したという事実を隠して例外を飲み込むことです。 try..finally
はあなたのクリーンアップコードを実行し、例外はそれをどうするかを知っている何かによって処理され続けるでしょう。
撮影場所: hereから
メソッドの実行の成功の一環として例外の発生とキャッチをルーチンに行うべきではありません。 クラスライブラリを開発する場合、例外を発生させる可能性のある操作を実行する前に、クライアントコードにエラー条件をテストする機会を与えなければなりません。 たとえば、System.IO.FileStreamは、次のコードスニペットに示すように、Readメソッドを呼び出す前に確認できるCanReadプロパティを提供し、潜在的な例外が発生するのを防ぎます。
Dim str As Stream = GetStream()If(str.CanRead)Thenストリームを読み込むコードEnd If
例外を発生させる可能性のある特定のメソッドを呼び出す前に、オブジェクトの状態をチェックするかどうかは、オブジェクトの予期される状態によって決まります。 FileStreamオブジェクトが存在するはずのファイルパスと読み取りモードでファイルを返すコンストラクタを使用して作成された場合、CanReadプロパティをチェックする必要はありません。 FileStreamを読み取ることができないことは、作成されたメソッド呼び出しの予想される動作に違反するため、例外を発生させる必要があります。 対照的に、メソッドがFileStream参照を返すものとして文書化されている場合は、CanReadプロパティをチェックしてからデータを読み込むことをお勧めします。
「実行時例外」コーディング手法を使用すると、キャストが失敗した場合にInvalidCastExceptionをスローするキャストのパフォーマンスがC#as演算子と比較され、キャストに失敗した場合はnullを返すパフォーマンスへの影響を示すことができます。 2つのテクニックのパフォーマンスは、キャストが有効な場合(Test 8.05を参照)と同じですが、キャストが無効でキャストを使用すると例外が発生する場合、キャストを使用するのはキャストを使用するより600倍遅くなります(テスト8.06を参照)。 例外スロー技法の高性能の影響には、例外の割り振り、スロー、キャッチ、および例外オブジェクトの後続のガベージコレクションのコストが含まれます。これは、例外をスローする瞬間的な影響がそれほど高くないことを意味します。 より多くの例外がスローされると、頻繁なガベージコレクションが問題になるため、例外をスローするコーディング手法を頻繁に使用することによる全体的な影響は、テスト8.05に似ています。
最後にオプションです。クリーンアップするリソースがない場合は、「最後に」ブロックを持つ必要はありません。
最後に何があっても実行されます。 したがって、tryブロックが成功した場合は実行され、tryブロックが失敗するとcatchブロック、finallyブロックが実行されます。
また、次の構文を使用することをお勧めします。
using (StreamReader reader=new StreamReader("myfile.txt"))
{
}
usingステートメントは自動的にtry / finallyでラップされ、ストリームは自動的に閉じられます。 (実際に例外をキャッチする場合は、usingステートメントの前後にtry / catchを配置する必要があります)。
私はコンセンサスのようなものに同意します。空の 'キャッチ'は、tryブロックで発生した可能性のある例外をマスクするので悪いです。
また、読みやすさの観点から、私が 'try'ブロックを見ると、対応する 'catch'ステートメントがあると仮定します。 'finally'ブロックでリソースが割り当て解除されるように 'try'のみを使用している場合は、代わりに'using'ステートメントを使用することを検討してください 。
using (StreamReader reader = new StreamReader('myfile.txt'))
{
// do stuff here
} // reader.dispose() is called automatically
IDisposableを実装する任意のオブジェクトで 'using'ステートメントを使用できます。 オブジェクトのdispose()メソッドは、ブロックの最後に自動的に呼び出されます。
読みやすさの観点からは、将来のコードリーダーに「これは重要であり、何が起こったとしても実行する必要があります」と明示しています。 これはいい。
また、空のcatchステートメントは、特定の「匂い」を持つ傾向があります。 開発者が発生する可能性のあるさまざまな例外やその対処方法を考えていないという印があるかもしれません。