私はtry-catchに関する質問を見たことがあります。(Jon Skeetを含め)空のcatchブロックは本当に悪い考えだと言っていますか?なんでこれ?空のキャッチが間違った設計決定ではない状況はありませんか?
たとえば、どこかから追加の情報(Webサービス、データベース)を取得したい場合があり、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとし、何かが起こっても大丈夫です、私は単に「キャッチ(例外は無視されました){}」を追加し、それですべてです
私はtry-catchに関する質問を見たことがあります。(Jon Skeetを含め)空のcatchブロックは本当に悪い考えだと言っていますか?なんでこれ?空のキャッチが間違った設計決定ではない状況はありませんか?
たとえば、どこかから追加の情報(Webサービス、データベース)を取得したい場合があり、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとし、何かが起こっても大丈夫です、私は単に「キャッチ(例外は無視されました){}」を追加し、それですべてです
回答:
エラー状態を黙って飲み込んでから実行を続けるため、通常は空のtry-catchはお勧めできません。時々、これは正しいことかもしれませんが、多くの場合、開発者が例外を見つけ、それについて何をすべきかわからず、空のキャッチを使用して問題を沈黙させたことを示しています。
これは、エンジン警告灯の上に黒いテープを置くのと同等のプログラミングです。
例外をどのように処理するかは、ソフトウェアのどのレイヤーで作業しているのかによって異なると思います:Exceptions in the Rainforest。
これは、障害(より一般的には例外的な状態)が適切に満たされ、応答がまったくない本当にまれな状態であるため、一般的には悪い考えです。その上、空のcatch
ブロックは、例外エンジンを使用して、プリエンプティブに実行する必要があることをエラーチェックする人々が使用する一般的なツールです。
それが常に悪いと言うのは本当ではない...それはほとんど本当ではない。エラーが発生したことを気にしないか、エラーの存在がどういうわけかそれについて何もできないことを示している場合があります(たとえば、以前のエラーをテキストログファイルに書き込んだり、と表示されますIOException
。つまり、新しいエラーを書き出すことができませんでした)。
空のcatchブロックを使用するのは悪いプログラマーであり、彼が何をしているのかわからない、とまでは言いません。
必要に応じて、空のcatchブロックを使用します。時々、私が消費しているライブラリのプログラマーは、彼が何をしているかわからず、だれもそれを必要としない状況でも例外をスローします。
たとえば、いくつかのhttpサーバーライブラリについて考えてみましょindex.html
う。クライアントが切断されて送信できなかったためにサーバーが例外をスローしたとしても、それほど気にすることはできませんでした。
正当化できるまれな例があります。Pythonでは、次のような構成がよく見られます。
try:
result = foo()
except ValueError:
result = None
したがって、(アプリケーションによっては)実行しても問題ない場合があります。
result = bar()
if result == None:
try:
result = foo()
except ValueError:
pass # Python pass is equivalent to { } in curly-brace languages
# Now result == None if bar() returned None *and* foo() failed
最近の.NETプロジェクトでは、特定のインターフェイスを実装するクラスを見つけるためにプラグインDLLを列挙するコードを記述する必要がありました。関連するコード(VB.NETでは申し訳ありません)は次のとおりです。
For Each dllFile As String In dllFiles
Try
' Try to load the DLL as a .NET Assembly
Dim dll As Assembly = Assembly.LoadFile(dllFile)
' Loop through the classes in the DLL
For Each cls As Type In dll.GetExportedTypes()
' Does this class implement the interface?
If interfaceType.IsAssignableFrom(cls) Then
' ... more code here ...
End If
Next
Catch ex As Exception
' Unable to load the Assembly or enumerate types -- just ignore
End Try
Next
この場合でも、どこかに障害を記録することはおそらく改善になると認めます。
空のcatchブロックは通常、コーダーが実際に何をしているのかわからないために挿入されます。私の組織では、空のcatchブロックに、例外を除いて何もしないことが良い考えである理由に関するコメントを含める必要があります。
関連する注意として、ほとんどの人はtry {}ブロックの後にcatch {}またはfinally {}を続けることができることを知りませんが、必要なのは1つだけです。
例外は、本当に例外がある場合にのみスローする必要があります-何かが標準を超えて起こっています。空のcatchブロックは基本的に「何か悪いことが起こっていますが、私は気にしません」と言っています。これは悪い考えです。
例外を処理したくない場合は、例外を処理できるコードに到達するまで、例外を上方に伝播させます。例外を処理できるものがなければ、アプリケーションを停止する必要があります。
catch (Exception) {}
悪い考えですcatch (SpecificExceptionType) {}
が、完全に良いかもしれません。プログラマーは、catch節の型情報を使用して、例外を検査します。
パージョシュブロッホ - 項目65:Doが例外無視しないの効果的なJavaの:
空のcatchブロックは、本質的に「どのエラーがスローされたのか知りたくないので、無視するだけです」と言っています。
これはVB6と似てOn Error Resume Next
いますが、例外がスローされた後のtryブロックのすべてがスキップされる点が異なります。
これは、何かが壊れたときに役に立ちません。
考えられるすべての例外を黙って渡しているため、これはおそらく正しいことではありません。予期している特定の例外がある場合は、それをテストし、例外でない場合は再スローする必要があります。
try
{
// Do some processing.
}
catch (FileNotFound fnf)
{
HandleFileNotFound(fnf);
}
catch (Exception e)
{
if (!IsGenericButExpected(e))
throw;
}
public bool IsGenericButExpected(Exception exception)
{
var expected = false;
if (exception.Message == "some expected message")
{
// Handle gracefully ... ie. log or something.
expected = true;
}
return expected;
}
一般に、実際に処理できる例外のみをキャッチする必要があります。つまり、例外をキャッチするときはできるだけ具体的にします。すべての例外をキャッチすることはめったになく、すべての例外を無視することはほとんど常に非常に悪い考えです。
空のcatchブロックがいくつかの意味のある目的を持っているいくつかの例だけを考えることができます。特定の例外が発生しても、アクションを再試行するだけでキャッチされている場合は、「キャッチ」ブロックで何もする必要はありません。ただし、例外が発生したという事実をログに記録することをお勧めします。
別の例:CLR 2.0は、ファイナライザスレッドの未処理の例外の処理方法を変更しました。2.0より前のバージョンでは、プロセスはこのシナリオに耐えることができました。現在のCLRでは、ファイナライザスレッドで未処理の例外が発生した場合、プロセスが終了します。
ファイナライザが本当に必要な場合にのみファイナライザを実装し、それでもファイナライザで可能な限り少しを行う必要があることに注意してください。ただし、ファイナライザが実行する必要がある作業が例外をスローする可能性がある場合は、2つの悪の小さい方を選択する必要があります。未処理の例外が原因でアプリケーションをシャットダウンしますか?または、多かれ少なかれ未定義の状態で続行しますか?少なくとも理論的には、後者はいくつかのケースでは2つの悪のうち小さい方かもしれません。これらの場合、空のcatchブロックはプロセスの終了を妨げます。
たとえば、どこかから追加の情報(Webサービス、データベース)を取得したい場合があり、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとし、何かが起こっても大丈夫です、私は単に「キャッチ(例外は無視されました){}」を追加し、それですべてです
したがって、あなたの例を考えると、すべての例外をキャッチして無視しているので、その場合はお勧めできません。捕まえEInfoFromIrrelevantSourceNotAvailable
てそれを無視していたとしても、それは問題ありませんが、そうではありません。またENetworkIsDown
、を無視しているため、重要な場合とそうでない場合があります。あなたは無視しているENetworkCardHasMelted
とEFPUHasDecidedThatOnePlusOneIsSeventeen
、これらはほぼ間違いなく重要です。
重要でないとわかっている特定のタイプの例外のみをキャッチ(および無視)するように設定されている場合、空のcatchブロックは問題になりません。すべての例外を抑制し、黙って無視することをお勧めします。最初に例外を調べて、それらが予期されている/正常/無関係であるかどうかを確認するのを止めることはありませんが、非常にまれです。
あなたがそれらを使用するかもしれない状況がありますが、それらは非常にまれであるべきです。私が使用する可能性のある状況は次のとおりです。
例外ロギング。コンテキストによっては、未処理の例外またはメッセージをポストする必要がある場合があります。
レンダリング、サウンド処理、リストボックスコールバックなどの技術的な状況のループ。動作自体が問題を実証し、例外をスローすると邪魔になり、例外をログに記録すると、おそらく「数百のXXXに失敗」というメッセージが表示されます。 。
少なくとも何かをログに記録しているはずですが、失敗することのないプログラム。
ほとんどのwinformsアプリケーションでは、すべてのユーザー入力に対して1つのtryステートメントがあれば十分であることがわかりました。私は次の方法を使用します:(AlertBoxは単なるMessageBox.Showラッパーです)
public static bool TryAction(Action pAction)
{
try { pAction(); return true; }
catch (Exception exception)
{
LogException(exception);
return false;
}
}
public static bool TryActionQuietly(Action pAction)
{
try { pAction(); return true; }
catch(Exception exception)
{
LogExceptionQuietly(exception);
return false;
}
}
public static void LogException(Exception pException)
{
try
{
AlertBox(pException, true);
LogExceptionQuietly(pException);
}
catch { }
}
public static void LogExceptionQuietly(Exception pException)
{
try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { }
}
次に、すべてのイベントハンドラーは次のような処理を実行できます。
private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs)
{
EditorDefines.TryAction(Dispose);
}
または
private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs)
{
EditorDefines.TryActionQuietly(() => Render(pEventArgs));
}
理論的には、TryActionSilentlyを使用できます。これは、例外が無限のメッセージを生成しないように、呼び出しのレンダリングに適している場合があります。
catchブロックで何をすべきかわからない場合は、この例外をログに記録できますが、空白のままにしないでください。
try
{
string a = "125";
int b = int.Parse(a);
}
catch (Exception ex)
{
Log.LogError(ex);
}