web-dev-qa-db-ja.com

スタックトレースをリセットせずに例外をスローする方法は?

これは 「throw」と「throwex」の間に違いはありますか へのフォローアップの質問です。

スタックトレースをリセットせずに新しいエラー処理メソッドを抽出する方法はありますか?

[編集]「内部メソッド」とEarwickerが提供する別の 回答 の両方を試し、どちらがうまくいくかを確認します答えをマークする方が良いです。

23
dance2die

あなたがそれを意味するかどうかはわかりませんが、あなたの他の質問での私の提案はこれに対処することでした。

例外が処理されたかどうかに関係なく、ハンドラーがブール値を返す場合は、catch句でこれを使用できます。

catch (Exception ex) {
  if (!HandleException(ex)) {
    throw;
  }
}
27
Lucero

はい;それがInnerExceptionプロパティの目的です。

catch(Exception ex)
{
    throw new YourExceptionClass("message", ex);
}

これにより、独自のロジックを追加してから、独自の例外クラスをスローできます。 YourExceptionClassインスタンスのStackTraceはこのコードブロック内にありますが、InnerExceptionは、以前に発生したStackTraceでキャッチした例外になります。

44
Adam Robinson

.NET Framework 4.5では、この正確なシナリオをサポートする ExceptionDispatchInfo があります。これにより、含まれているスタックトレースを上書きすることなく、完全な例外をキャプチャして別の場所から再スローできます。

コメントでのリクエストによるコードサンプル

using System.Runtime.ExceptionServices;

class Test
{
    private ExceptionDispatchInfo _exInfo;

    public void DeleteNoThrow(string path)
    {
        try { File.Delete(path); }
        catch(IOException ex)
        {
            // Capture exception (including stack trace) for later rethrow.
            _exInfo = ExceptionDispatchInfo.Capture(ex);
        }
    }

    public Exception GetFailure()
    {
        // You can access the captured exception without rethrowing.
        return _exInfo != null ? _exInfo.SourceException : null;
    }

    public void ThrowIfFailed()
    {
        // This will rethrow the exception including the stack trace of the
        // original DeleteNoThrow call.
        _exInfo.Throw();

        // Contrast with 'throw GetFailure()' which rethrows the exception but
        // overwrites the stack trace to the current caller of ThrowIfFailed.
    }
}
43
Zarat

元のスタックトレースを使用して新しい例外を作成する必要はありません。そのスタックトレースは新しい例外を作成しなかったので、これは誤解を招く恐れがあります。

ただし、元の例外を「InnerException」として新しい例外に含めることができます。それはあなたが探していることをしますか?

5
Brian Genisio

より慎重にフィルタリングしたい例外をキャッチしているので、考えを変えて、それらを処理しないことを決定して、それらを再スローすることができますか?

これに本当に注意したいのなら、それは本当に良い考えではありません。そもそも例外をキャッチしない方がいいです。その理由は、特定のtry/catchハンドラーが、予期しない例外に対してネストされたfinallyブロックを実行する決定を下すべきではないためです。たとえば、NullReferenceExceptionがある場合、別のそのような例外がスローされる可能性があるため、コードの実行を継続することはおそらく非常に悪い考えです。また、finallyブロックは、他のコードと同様に単なるコードです。例外が初めてキャッチされるとすぐに、try/catchの下のスタック上のfinallyブロックが実行され、それまでに手遅れになります。別の例外が生成される可能性があります。これは、元の例外が失われること。

これは、(C#では)キャッチしたいすべての例外タイプに対して個別のcatchハンドラーを注意深く書き出す必要があることを意味します。また、例外タイプでのみフィルタリングできることも意味します。これは、従うのが非常に難しいアドバイスである場合があります。

他の方法で例外をフィルタリングすることは可能ですが、C#ではそうではありません。ただし、VB.NETで可能であり、BCL自体がVB.NETで少量のコードを記述してこれを利用しているため、より便利な方法で例外をフィルタリングできます。

CLRチームのブログからのVB.NETコードサンプルを含む詳細な説明があります。

そしてこれが私の2セントです。

2