17

非常に単純な例外がスローされ、同じメソッドでキャッチされるという珍しいケースがあります。 それは再スローされません(ナイーブなプログラマーが抱える通常の種類の問題)。それでも、そのStackFrameには現在のメソッドが1つだけ含まれています。外観は次のとおりです。

   at (my class).MyMethod() in C:\(my file path and line)

実際には、VS2010デバッガーの呼び出しスタックには、これに至るまでにおそらく30のメソッドがあり、半ダースの異なるアセンブリにまたがっています。これらすべてを最適化することは不可能のようです。さらに、このコードは、.NET 4用に、最適化なしでデバッグモードで構築されています。( http://msdn.microsoft.com/en-us/library/9dd8z24x.aspxに基づいて).iniファイル(1つを含む)もあります。同じフォルダ内の[app].vshost.ini)という名前:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

また、メソッド呼び出しはメソッドの最後ではないため、末尾再帰の最適化はさらに可能性が低いようです。

それがどのように呼び出されるかについて:呼び出しスタックでのリフレクションの使用はなく、いかなる種類のInvoke()またはBeginInvoke()もありません。これは、ボタンのクリックからの呼び出しの長いチェーンです。クリックハンドラーは、コールスタックを約10回呼び出します。その下には、通常のWndProc、NativeWindow.Callback、ネイティブ/マネージドトランジション、およびメッセージループがあります。これは最終的に、C#EXEアセンブリから実行されるShowDialog()呼び出しの内部にあります。

これで、catchハンドラーでStackTraceクラスのインスタンスを作成できることがわかりました。また、Exceptionオブジェクトを渡すと、呼び出しスタックも短くなります。代わりに、引数なしでnew StackTrace()を呼び出すと、完全な呼び出しスタックが生成されます。

例外クラスの内部がスローされ、その呼び出しスタックが構築されるようにデバッグするためにReflectorを使用しましたが、ExceptionまたはStackTraceにブレークポイントを設定できませんでした。それらをEnvironment.GetStackTrace()で設定でき、このメソッド(Exceptionが呼び出す)は、構築およびスロープロセス中に呼び出されないように見えますが、デバッガーが実際に正しく機能しているかどうかはわかりません。(ただし、このメソッドは他のいくつかの目的でトリガーされるため、どうすればよいかわかりません。)

メソッドの抜粋は次のとおりです。

private void MyMethod()
{
    ...               
    try
    {
        throw new ApplicationException("Test failure");
    }
    catch (Exception e)
    {
        StackTrace stackTrace1 = new StackTrace(e);
        StackTrace stackTrace2 = new StackTrace(e, false);
        StackTrace stackTrace3 = new StackTrace(e, true);
        StackTrace stackTrace4 = new StackTrace();
        string STs = stackTrace1.ToString() + "\n---\n"
            + stackTrace2.ToString() + "\n---\n"
            + stackTrace3.ToString() + "\n---\n"
            + stackTrace4.ToString();
        Log(EventSeverity.Debug, STs);
        ...
        }
    }

非常に簡単です。例外をスローし、キャッチしてログに記録します。

デバッガーでもスタンドアロンでも同じ結果が得られます—1行の呼び出しスタック。そして、私はこの問題をコードベースの他の場所で見たことがあることを知っています。以前は、例外を再スローしたことが原因だと思っていましたが、多くの場合、最初のcatchブロック内にログを記録します。私はかなり困惑していて、私が行ったすべてのWeb検索は何も生成していません。


これは、提供された回答にコメントとして追加するには少し多すぎますが、ここにいくつかの詳細情報があります。

この動作は http://dotnetthoughts.wordpress.com/2007/10/27/where-did-my-exception-occur/で説明されており、実際にはhttp://msdn.microsoftで説明されていることがわかります。 com / en-us / library / system.exception.stacktrace.aspx(ただし、彼らがそこで言っていることを簡単に見逃す可能性があると思います)。

ですから、私の「解決策」はちょっとした失敗になると思います。例外をフォーマットするために通常呼び出す中央メソッドがあります。そのメソッド内で、Exceptionオブジェクトがある場合とない場合の両方で新しいStackTrace()を作成します。次に、Exceptionのスタックトレースの一番下にあるメソッドを探し、その下にあるすべてのものを新しいStackTrace()に表示して、一連の呼び出しによって呼び出されたことを示します。

もちろん、欠点は、この方法を使用しないと、情報がそこにないことです。しかし、私はどこかで何らかのコード変更を期待しなければなりませんでした。

4

1 に答える 1

19

例外がスローされると、プロパティで部分的なスタックトレースのみが使用されException.StackTraceます。スタックには、例外をキャッチしているメソッドまでの呼び出しのみが表示されます。(すでに述べたように)完全なスタックを取得するには、new StackTrace()オブジェクトを作成する必要があります。

現時点ではリンクが見つかりませんが、スタックトレースは、例外をスローしながらスタックを上に移動することで作成されていると思います。例外がcatchブロックに達すると、スタックはコンパイルを停止します。したがって、部分的なスタックしか得られません。

通常、catchブロックは、誰がそれを呼び出したかではなく、例外がどこから発生したかには関係しません。

于 2011-03-14T17:13:39.837 に答える