9

私がしたいのは、例外が発生したときに例外をレベルアップすることだけですか?

private void TryCatch()
{
   try
   {
       foo();
   }
   catch (Exception ex)
   {
       throw;
   }
}

private void NoTryCatch()
{
   foo();
}

これらの 2 つの方法は同じではありませんか?

TryCatch で例外が発生した場合は 1 レベル上にスローされ、NoTryCatch で例外が発生した場合は 1 レベル上にスローされます。

この質問は、ReSharper を使用して、try/catch ブロックが冗長であるため削除するよう提案されていることに気付いた後に発生しました。

4

8 に答える 8

19

はい、それらの方法はほとんど(*)同じです。唯一の違いは、最初のブレークポイントにブレークポイントを設定するのが簡単なことです。私が本当にそこにそしてそこにだけ壊す必要がない限り、私はいつも2番目に行きます(すぐにそのタイプの例外がスローされたのとは対照的に、それは簡単でしょう)。最初のフォームを使用したことがある場合でも、コードをコミットする前に2番目のフォームに戻します。

(*)JITがそれらを処理する方法に関しては、いくつかの違いがあるかもしれません。最初のものはより多くのILになり、インライン化などの機会に影響を与えます。

編集:私は少しのマイクロベンチマークに抵抗することはできません。try / catch / throwは、インライン化を無効にするだけでなく、パフォーマンスに厄介な影響を与えるようです。

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

public class Test
{
    const int Iterations = 1000000000;

    static void Main()
    {
        Stopwatch sw;

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            SimpleMethod();
        }
        sw.Stop();
        Console.WriteLine("Simple method: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            NoInlining();
        }
        sw.Stop();
        Console.WriteLine("No inlining: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            TryCatchThrow();
        }
        sw.Stop();
        Console.WriteLine("try/catch/throw: {0}", sw.ElapsedMilliseconds);
    }

    static void SimpleMethod()
    {
        Foo();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static void NoInlining()
    {
    }

    static void TryCatchThrow()
    {
        try
        {
            Foo();
        }
        catch (Exception)
        {
            throw;
        }
    }

    static void Foo() {}
}

でコンパイル/o+ /debug-

結果(3回の実行):

簡単な方法: 504、495、489
インライン化なし:
2977、3060、3019試行/キャッチ/スロー:5274、4543、5145

于 2009-01-10T21:23:04.520 に答える
3

いいえ、try catch は必要ありません。最初の関数を使用する唯一の理由は、関数をさらに処理する前に、ログを記録したり、リソースを解放したりする場合です。

于 2009-01-10T21:21:57.300 に答える
1

これら 2 つの方法は本質的に同じです。この場合、ReSharper はその提案で正しかったです。

于 2009-01-10T21:21:52.963 に答える
1

それらは実際には同じではありません。Throw単独で、またはthrow exスタック トレース情報を台無しにして、デバッグを困難にする可能性があります。

例外をキャッチする最善の理由は、次のようなコンテキストをスタック トレースに追加することです。

try {
  Foo();
}
catch (Exception e) {
  throw new BetterException("I did something slightly silly", e);
}
于 2009-01-10T23:10:13.807 に答える
1

と思ったのですが、100%確信が持てなかったので調べてみました。時々、私は正しかった。

どうやら、コードが行っている例外を再スローすると、スタックトレースが変更される可能性があります。まず第一に、それを書くthrow ex;とスタックトレースがリセットされます。第二に、書いてthrow;いても情報が抜けている場合もあります。この記事とそれに続くいくつかのユーザーのコメントを参照してください。

もちろん、これらの問題のほとんどは重要なスタック トレースと行番号に関連していますが、インライン化 (またはその欠如) だけでなく、全体的なパフォーマンスにも影響すると思いました。オーバーヘッドをキャッチしてスローする例外ですが、これについて具体的なものは見つかりませんでした。

于 2009-01-10T22:35:46.823 に答える
0

ReSharperは正しいです。実際に例外をキャッチして何かをするつもりでない限り、try..catchブロックを含めても意味がありません。

于 2009-01-10T21:22:26.660 に答える
0

はい、trycatchブロックは冗長です。例外を処理するtry/catchが見つかるまで、スタックは巻き戻されます。

于 2009-01-10T21:22:32.807 に答える
0

例外を再スローするだけの場合は、try/catchブロックは必要ありません。通常、例外を処理できる場合にのみ例外をキャッチする必要があります。それ以外の場合は、それらを上向きに伝播させます。

于 2009-01-10T21:22:35.600 に答える