C#で例外をキャッチして再スローするのはなぜですか?

580
corlettk 2009-05-19 21:56.

記事C#-シリアル化可能なDTOのデータ転送オブジェクトを見ています。

この記事には、次のコードが含まれています。

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

記事の残りの部分は(初心者に)正気で合理的に見えますが、そのtry-catch-throwはWtfExceptionをスローします...これは例外をまったく処理しないこととまったく同じではありませんか?

エルゴ:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

または、C#でのエラー処理に関する基本的な何かが欠けていますか?Java(チェックされた例外を除く)とほとんど同じですよね?...つまり、どちらもC ++を改良しました。

スタックオーバーフローの質問パラメータなしのキャッチを再スローすることと何もしないことの違いは?try-catch-throwは-no-opであるという私の主張を支持しているようです。


編集:

将来このスレッドを見つけた人のために要約すると...

しない

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

スタックトレース情報は、問題の根本原因を特定するために重要な場合があります。

行う

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

(Javaのように)具体性の低い例外の前に、より具体的な例外をキャッチします。


参照:

  • MSDN-例外処理
  • MSDN-try-catch(C#リファレンス)

17 answers

449
Fredrik Mörk 2009-05-19 22:02.

最初; 記事のコードがそれを行う方法は悪です。throw ex例外の呼び出しスタックを、このthrowステートメントがあるポイントにリセットします。例外が実際に作成された場所に関する情報が失われます。

次に、そのようにキャッチして再スローした場合、付加価値は見られません。上記のコード例throw exは、try-catchがなくても同じくらい良い(または、少し言えばさらに良い)でしょう。

ただし、例外をキャッチして再スローしたい場合があります。ロギングはそれらの1つである可能性があります。

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}
121
Eoin Campbell 2009-05-19 22:03.

これをしないでください、

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

スタックトレース情報が失われます...

どちらか、

try { ... }
catch { throw; }

または

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

再スローする理由の1つは、たとえば、さまざまな例外を処理している場合です。

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}
58
bzlm 2009-05-19 22:20.

C#(C#6より前)はVBがサポートするCILの「フィルターされた例外」をサポートしていないため、C#1-5で例外を再スローする理由の1つは、catch()の時点で十分な情報がないことです。実際に例外をキャッチするかどうかを決定します。

たとえば、VBでは次のことができます

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

...これは、異なるErrorCode値を持つMyExceptionsを処理しません。v6より前のC#では、ErrorCodeが123でない場合、MyExceptionをキャッチして再スローする必要がありました。

try 
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

C#6.0以降、VBと同じようにフィルタリングできます。

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}
18
Noname 2009-09-18 23:50.

次のようなコードを持つ私の主な理由:

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

これは、インスタンス化された例外オブジェクトを持つキャッチにブレークポイントを設定できるようにするためです。私は開発/デバッグ中にこれをたくさん行います。もちろん、コンパイラは未使用のすべてのeについて警告を表示します。理想的には、リリースビルドの前にそれらを削除する必要があります。

ただし、デバッグ中は便利です。

11
edosoft 2009-05-19 22:03.

例外を再スローする正当な理由は、例外に情報を追加したい場合、または元の例外を独自の作成の1つでラップしたい場合です。

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}
10
Arjan Einbu 2009-05-19 22:11.

これは、例外をまったく処理しないこととまったく同じではありませんか?

正確には、それは同じではありません。例外のスタックトレースをリセットします。これはおそらく間違いであり、したがって悪いコードの例であることに同意します。

8
Duncan 2009-05-19 22:02.

exをスローしたくない-これはコールスタックを失うからです。例外処理(MSDN)を参照してください。

そして、はい、try ... catchは何の役にも立ちません(何らかの理由でこの情報を公開したくない場合を除いて、コールスタックが失われることを除けば-実際にはもっと悪いです-)。

5
supercat 2013-10-15 06:56.

人々が言及していない点は、.NET言語は実際には適切な区別をしていませんが、例外が発生したときにアクションを実行する必要あるかどうか、およびそれを解決するかどうかの問題は、実際には別個の質問であるということです。解決する見込みのない例外に基づいてアクションを実行する必要がある場合が多く、例外を「解決」するために必要なのは、スタックを特定のポイントに巻き戻すことだけである場合もあります。それ以上のアクションは必要ありません。 。

「処理」できるものだけを「キャッチ」する必要があるという一般的な知恵のため、例外が発生したときにアクションを実行する必要がある多くのコードはそうではありません。たとえば、多くのコードはロックを取得し、保護されたオブジェクトを「一時的に」その不変条件に違反する状態にし、次にオブジェクトを正当な状態にし、他の誰かがオブジェクトを見る前にロックを解除します。オブジェクトが危険なほど無効な状態にあるときに例外が発生した場合、一般的な方法は、オブジェクトをその状態のままにしてロックを解除することです。より良いパターンは、オブジェクトが「危険な」状態にあるときに発生する例外を明示的に無効にすることです。これにより、今後ロックを取得しようとするとすぐに失敗します。このようなパターンを一貫して使用すると、いわゆる「ポケモン」例外処理の安全性が大幅に向上します。IMHOは、主に、最初に適切なアクションを実行せずに例外を浸透させるコードが原因で評判が悪くなります。

ほとんどの.NET言語では、コードが例外に基づいてアクションを実行する唯一の方法は、コードに対してcatch(例外を解決しないことがわかっている場合でも)、問題のアクションを実行してから再実行することthrowです)。コードがどの例外がスローされるかを気にしない場合の別の可能なアプローチはoktry/finallyブロックでフラグを使用することです。セットokにフラグをfalseブロックする前に、とにtrueブロックが終了する前に、および任意の前にreturnブロック内だという。次に、内でfinallyokが設定されていない場合、例外が発生したに違いないと想定します。このようなアプローチは、意味的にはcatch/よりも優れていますが、throw醜く、本来よりも保守が困難です。

5
Jackson Tarisa 2018-05-28 05:35.

これは、プログラミングがライブラリまたはdll用に機能する場合に役立ちます。

この再スロー構造を使用して、呼び出しスタックを意図的にリセットし、関数内の個々の関数からスローされた例外を確認する代わりに、関数自体から例外を取得することができます。

これは、スローされた例外がよりクリーンになり、ライブラリの「ルート」に入らないようにするために使用されていると思います。

4
statler 2016-08-10 01:47.

他の多くの回答は、例外を再スローする理由の良い例を提供しますが、「最終的に」シナリオについて言及した人はいないようです。

この例は、カーソルを(たとえば、待機カーソルに)設定するメソッドがあり、メソッドにいくつかの出口点があり(たとえば、()return;)、カーソルがでリセットされるようにしたい場合です。メソッドの終わり。

これを行うには、すべてのコードをtry / catch / finallyでラップします。最後に、カーソルを右カーソルに戻します。有効な例外を埋めないように、キャッチに再スローします。

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}
3
Brian 2009-07-31 05:12.

キャッチスローの考えられる理由の1つは、スタックのより深いところにある例外フィルターがフィルターダウンされないようにすることです(ランダムな古いリンク)。しかしもちろん、それが意図されていれば、そこにそう言っているコメントがあるでしょう。

3
Pondidum 2009-05-19 22:04.

それはあなたがcatchブロックで何をしているか、そしてあなたがエラーを呼び出し元のコードに伝えたいかどうかに依存します。

Catch io.FileNotFoundExeption ex別のファイルパスなどを言ってから使用しても、エラーが発生します。

また、Throw代わりにThrow Ex実行すると、完全なスタックトレースを保持できます。Throw exは、throwステートメントからスタックトレースを再開します(それが理にかなっていることを願っています)。

2
Sheff 2009-05-19 22:19.

あなたが投稿したコードの例では、実際には、例外をキャッチする意味はありません。キャッチには何も行われていないため、再スローされるだけです。実際、コールスタックが失われるため、害はありません。 。

ただし、例外が発生した場合は、例外をキャッチしてロジックを実行し(たとえば、ファイルロックのSQL接続を閉じる、またはログを記録する)、呼び出し元のコードにスローして処理します。これは、ビジネスレイヤーを実装するコーダーに例外を処理させたい場合があるため、フロントエンドコードよりもビジネスレイヤーで一般的です。

繰り返しになりますが、投稿した例で例外をキャッチする意味はありません。そのようにしないでください!

1
Noname 2009-09-16 21:22.

申し訳ありませんが、「改良されたデザイン」などの多くの例は、依然としてひどいにおいがするか、非常に誤解を招く可能性があります。{} catch {log; throw}はまったく無意味です。例外ログは、アプリケーション内の中央の場所で実行する必要があります。とにかく例外がスタックトレースをバブルアップします。システムの境界の近くのどこかに例外を記録してみませんか?

コンテキスト(つまり、1つの例ではDTO)をログメッセージにシリアル化する場合は注意が必要です。ログファイルにアクセスできるすべての人の手に渡りたくない機密情報を簡単に含めることができます。また、例外に新しい情報を追加しない場合、例外の折り返しのポイントは実際にはわかりません。古き良きJavaにはそのためのいくつかのポイントがあります。呼び出し元は、コードを呼び出すときに予想される例外の種類を知っている必要があります。.NETにはこれがないため、私が見たケースの少なくとも80%では、ラッピングは何の役にも立ちません。

1
erikkallen 2009-09-23 09:53.

他の人が言ったことに加えて、キャッチと再スローはノーオペレーションではないことを示す関連する質問への私の答えを参照してください(VBにありますが、コードの一部はVBからC#で呼び出される可能性があります)。

1
Michael Freidgeim 2012-12-26 12:41.

シナリオcatch-log-rethrowについて話している回答のほとんど。

代わりにあなたのコードでそれを書き込むので、特に、AOPを使用することを検討しPostsharp.Diagnostic.Toolkit OnExceptionOptions IncludeParameterValueとIncludeThisArgumentで

0
Arsen Khachaturyan 2019-12-10 07:08.

を介して例外を再スローthrowすることは、現在の例外を処理する特定のコードがない場合、または特定のエラーケースを処理するロジックがあるが、他のすべてをスキップしたい場合に役立ちます。

例:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

ただし、catchブロックで条件節を使用して、これを行う別の方法もあります。

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

このメカニズムは、.NETランタイムが例外オブジェクトを再スローする前に再構築する必要がないため、例外を再スローするよりも効率的です。

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

今週のコミックコンですべての素晴らしいものに追いつく方法

今週のコミックコンですべての素晴らしいものに追いつく方法

サンディエゴコミックコンは今週開幕し、オタクのアナウンス、ポスター、予告編、お気に入りの番組や映画のからかいでいっぱいになります。SDCCは、コンベンションフロア全体の多くのパネルで行われているため、すべてに対応するのは難しい場合があります。

Googleの9千万ドルの和解はアプリ開発者にとってもGoogleにとっても勝利ですか?

Googleの9千万ドルの和解はアプリ開発者にとってもGoogleにとっても勝利ですか?

小さなアプリ開発者は金曜日に発表された法的な和解でグーグルから9千万ドルをこじ開けた。アップルとの同様の合意に続いて熱くなった。金曜日のブログ投稿で、Googleは、Androidメーカーが市場での優位性を悪用してPlayストア経由でのアプリ内購入に対して30%の料金を不当に請求したと主張するアプリ開発者との訴訟を解決するために、9千万ドルを支払うことに合意したと述べました。

RadioShackのTwitterはハッキングされていませんでした、それはただの暗号のサクラです

RadioShackのTwitterはハッキングされていませんでした、それはただの暗号のサクラです

今週、RadioShackのTwitterアカウントは、奇妙なものから完全にひどいものになりました。短い順序で、会社のフィード全体が、バイブレーター、「ビッグティット」(スペルミス)、有名人やその他の企業アカウントを荒らしているツイートなど、NSFW素材の真の山になりました。

ヒッグス粒子から10年後、物理学にとって次の大きなものは何ですか?

ヒッグス粒子から10年後、物理学にとって次の大きなものは何ですか?

大型ハドロン衝突型加速器のトンネル内にあるコンパクトミュオンソレノイド(CMS)検出器。2012年7月4日、CERNの科学者たちは、1960年代に最初に提案された素粒子であるヒッグス粒子の観測を確認しました。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Un breve viaje espacial sobre conceptualizar el diseño

Complicarse la vida, mezclar churros con meninas (nada de ovejas) y encontrar valor en un trastero que adquiriste en una puja.

Un breve viaje espacial sobre conceptualizar el diseño

Bien. Hay un momento en toda salida al espacio exterior en el que de la tensión, la velocidad y las altas temperaturas derivadas del cruce de estratosfera a ionosfera se pasa a un momento de súbita calma, donde se despliega la vista completa del paisaje espacial que nos rodea.

Seguindo Todos os Protocolos (2022), de Fábio Leal

Seguindo Todos os Protocolos (2022), de Fábio Leal

Chico quer transar. Até aí, tudo bem.

多元宇宙—Junø

多元宇宙—Junø

チェーン間アカウントがJunoに登場します。異なるブロックチェーン間でスマートコントラクトの構成可能性と真の相互運用性を提供します。

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「​​ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。

Language