記事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のように)具体性の低い例外の前に、より具体的な例外をキャッチします。
参照:
最初; 記事のコードがそれを行う方法は悪です。throw ex
例外の呼び出しスタックを、このthrowステートメントがあるポイントにリセットします。例外が実際に作成された場所に関する情報が失われます。
次に、そのようにキャッチして再スローした場合、付加価値は見られません。上記のコード例throw ex
は、try-catchがなくても同じくらい良い(または、少し言えばさらに良い)でしょう。
ただし、例外をキャッチして再スローしたい場合があります。ロギングはそれらの1つである可能性があります。
try
{
// code that may throw exceptions
}
catch(Exception ex)
{
// add error logging here
throw;
}
これをしないでください、
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
}
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
}
次のようなコードを持つ私の主な理由:
try
{
//Some code
}
catch (Exception e)
{
throw;
}
これは、インスタンス化された例外オブジェクトを持つキャッチにブレークポイントを設定できるようにするためです。私は開発/デバッグ中にこれをたくさん行います。もちろん、コンパイラは未使用のすべてのeについて警告を表示します。理想的には、リリースビルドの前にそれらを削除する必要があります。
ただし、デバッグ中は便利です。
例外を再スローする正当な理由は、例外に情報を追加したい場合、または元の例外を独自の作成の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);
}
}
これは、例外をまったく処理しないこととまったく同じではありませんか?
正確には、それは同じではありません。例外のスタックトレースをリセットします。これはおそらく間違いであり、したがって悪いコードの例であることに同意します。
exをスローしたくない-これはコールスタックを失うからです。例外処理(MSDN)を参照してください。
そして、はい、try ... catchは何の役にも立ちません(何らかの理由でこの情報を公開したくない場合を除いて、コールスタックが失われることを除けば-実際にはもっと悪いです-)。
人々が言及していない点は、.NET言語は実際には適切な区別をしていませんが、例外が発生したときにアクションを実行する必要があるかどうか、およびそれを解決するかどうかの問題は、実際には別個の質問であるということです。解決する見込みのない例外に基づいてアクションを実行する必要がある場合が多く、例外を「解決」するために必要なのは、スタックを特定のポイントに巻き戻すことだけである場合もあります。それ以上のアクションは必要ありません。 。
「処理」できるものだけを「キャッチ」する必要があるという一般的な知恵のため、例外が発生したときにアクションを実行する必要がある多くのコードはそうではありません。たとえば、多くのコードはロックを取得し、保護されたオブジェクトを「一時的に」その不変条件に違反する状態にし、次にオブジェクトを正当な状態にし、他の誰かがオブジェクトを見る前にロックを解除します。オブジェクトが危険なほど無効な状態にあるときに例外が発生した場合、一般的な方法は、オブジェクトをその状態のままにしてロックを解除することです。より良いパターンは、オブジェクトが「危険な」状態にあるときに発生する例外を明示的に無効にすることです。これにより、今後ロックを取得しようとするとすぐに失敗します。このようなパターンを一貫して使用すると、いわゆる「ポケモン」例外処理の安全性が大幅に向上します。IMHOは、主に、最初に適切なアクションを実行せずに例外を浸透させるコードが原因で評判が悪くなります。
ほとんどの.NET言語では、コードが例外に基づいてアクションを実行する唯一の方法は、コードに対してcatch
(例外を解決しないことがわかっている場合でも)、問題のアクションを実行してから再実行することthrow
です)。コードがどの例外がスローされるかを気にしない場合の別の可能なアプローチはok
、try/finally
ブロックでフラグを使用することです。セットok
にフラグをfalse
ブロックする前に、とにtrue
ブロックが終了する前に、および任意の前にreturn
ブロック内だという。次に、内でfinally
、ok
が設定されていない場合、例外が発生したに違いないと想定します。このようなアプローチは、意味的にはcatch
/よりも優れていますが、throw
醜く、本来よりも保守が困難です。
これは、プログラミングがライブラリまたはdll用に機能する場合に役立ちます。
この再スロー構造を使用して、呼び出しスタックを意図的にリセットし、関数内の個々の関数からスローされた例外を確認する代わりに、関数自体から例外を取得することができます。
これは、スローされた例外がよりクリーンになり、ライブラリの「ルート」に入らないようにするために使用されていると思います。
他の多くの回答は、例外を再スローする理由の良い例を提供しますが、「最終的に」シナリオについて言及した人はいないようです。
この例は、カーソルを(たとえば、待機カーソルに)設定するメソッドがあり、メソッドにいくつかの出口点があり(たとえば、()return;)、カーソルがでリセットされるようにしたい場合です。メソッドの終わり。
これを行うには、すべてのコードをtry / catch / finallyでラップします。最後に、カーソルを右カーソルに戻します。有効な例外を埋めないように、キャッチに再スローします。
try
{
Cursor.Current = Cursors.WaitCursor;
// Test something
if (testResult) return;
// Do something else
}
catch
{
throw;
}
finally
{
Cursor.Current = Cursors.Default;
}
キャッチスローの考えられる理由の1つは、スタックのより深いところにある例外フィルターがフィルターダウンされないようにすることです(ランダムな古いリンク)。しかしもちろん、それが意図されていれば、そこにそう言っているコメントがあるでしょう。
それはあなたがcatchブロックで何をしているか、そしてあなたがエラーを呼び出し元のコードに伝えたいかどうかに依存します。
Catch io.FileNotFoundExeption ex
別のファイルパスなどを言ってから使用しても、エラーが発生します。
また、Throw
代わりにThrow Ex
実行すると、完全なスタックトレースを保持できます。Throw exは、throwステートメントからスタックトレースを再開します(それが理にかなっていることを願っています)。
あなたが投稿したコードの例では、実際には、例外をキャッチする意味はありません。キャッチには何も行われていないため、再スローされるだけです。実際、コールスタックが失われるため、害はありません。 。
ただし、例外が発生した場合は、例外をキャッチしてロジックを実行し(たとえば、ファイルロックのSQL接続を閉じる、またはログを記録する)、呼び出し元のコードにスローして処理します。これは、ビジネスレイヤーを実装するコーダーに例外を処理させたい場合があるため、フロントエンドコードよりもビジネスレイヤーで一般的です。
繰り返しになりますが、投稿した例で例外をキャッチする意味はありません。そのようにしないでください!
申し訳ありませんが、「改良されたデザイン」などの多くの例は、依然としてひどいにおいがするか、非常に誤解を招く可能性があります。{} catch {log; throw}はまったく無意味です。例外ログは、アプリケーション内の中央の場所で実行する必要があります。とにかく例外がスタックトレースをバブルアップします。システムの境界の近くのどこかに例外を記録してみませんか?
コンテキスト(つまり、1つの例ではDTO)をログメッセージにシリアル化する場合は注意が必要です。ログファイルにアクセスできるすべての人の手に渡りたくない機密情報を簡単に含めることができます。また、例外に新しい情報を追加しない場合、例外の折り返しのポイントは実際にはわかりません。古き良きJavaにはそのためのいくつかのポイントがあります。呼び出し元は、コードを呼び出すときに予想される例外の種類を知っている必要があります。.NETにはこれがないため、私が見たケースの少なくとも80%では、ラッピングは何の役にも立ちません。
他の人が言ったことに加えて、キャッチと再スローはノーオペレーションではないことを示す関連する質問への私の答えを参照してください(VBにありますが、コードの一部はVBからC#で呼び出される可能性があります)。
シナリオcatch-log-rethrowについて話している回答のほとんど。
代わりにあなたのコードでそれを書き込むので、特に、AOPを使用することを検討しPostsharp.Diagnostic.Toolkit OnExceptionOptions IncludeParameterValueとIncludeThisArgumentで
を介して例外を再スロー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ランタイムが例外オブジェクトを再スローする前に再構築する必要がないため、例外を再スローするよりも効率的です。
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
ランボルギーニの創設者であるフェルッチオランボルギーニが100歳になるのは毎日ではありません(そうです、彼は死んでいて、まだ死んでいると思います。
Appleが自動車分野に参入するという噂はかなり前から渦巻いており、AppleウォッチャーがSixtyEight Researchという会社がAppleの自動車研究開発のシェル会社である可能性が高いと判断したとき、その渦巻きは本当に渦巻いた。また、会社が購入した車は1台だけであることが知られており、その車はAppleが何を考えているかについての手がかりでいっぱいになる可能性があることも伝えています。
太陽系の外側にある架空の大きな物体である惑星Xの探索は、何十年にもわたって人間を魅了してきました。その検索の最新の章は、地球の10倍の大きさで、公転周期が15であるほど遠くにある惑星を指しています。
カムニュートンは昨日、簡単な265ヤードと3回のタッチダウンでファルコンズを引き裂き、別の素晴らしいゲームをしました。その日のハイライトは、上のタッチダウンスローでした。これは、視聴するたびにばかげているだけです。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。