6

コードのルートにある種のキャッチオール例外メカニズムを持たせたいので、アプリが予期せず終了した場合でも、有用なログを提供できます。

の線に沿った何か

static void Main () {
    if (Debugger.IsAttached)
        RunApp();
    else {
        try {
            RunApp();
        }
        catch (Exception e) {
            LogException(e);
            throw;
        }
    }
 }

これはすべて正常に機能しますが、例外が発生した後にデバッガーをアタッチしたい場合に問題が発生します。

例外はランタイムにエスケープされるため、Windows は Visual Studio をアタッチするように求めますが、再スローされるため、スタックのさらに上のすべてのローカルとパラメーターが失われます。

デバッガをアタッチしてすべての有用な情報を保持する方法を提供しながら、これらの例外をログに記録する方法はありますか?

4

7 に答える 7

15

Paul Betts が既に述べたように、try/catch ブロックの代わりにAppDomain.UnhandledExceptionイベントを使用した方がよい場合があります。

UnhandledException イベント ハンドラーで、例外をログに記録/表示し、デバッグ オプションを提供できます。たとえば、例外の詳細と、無視、デバッグ、または終了するためのボタンを含むフォームを表示します。

ユーザーがデバッグ オプションを選択した場合は、System.Diagnostics.Debugger.Break()を呼び出します。これにより、ユーザーは必要なデバッガーをアタッチし、完全な呼び出しスタックを利用できるようになります。

明らかに、デバッガーを接続しないことがわかっているビルドに対しては、このオプションを無効にすることができます。

class Program
{
    static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += ExceptionHandler;

        RunApp();
    }

    static void ExceptionHandler(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.ExceptionObject);
        Console.WriteLine("Do you want to Debug?");
        if (Console.ReadLine().StartsWith("y"))
            Debugger.Break();
    }

    static void RunApp()
    {
        throw new Exception();
    }
}
于 2009-02-13T17:42:10.913 に答える
2

恐ろしくハックですが、ランタイムフックがなければ (私は何も知りません)、スロー元のスタックフレームに到達する唯一の方法です....

最終的にスローされることがわかっているすべての例外は、コンストラクターに次のものが必要です。

#if DEBUG
System.Diagnostics.Debugger.Launch()
#endif

これにより、ユーザーが関連するデバッガーを提供するか、no を選択するかを選択できるダイアログが表示され、デバッグは行われません (いずれの方法でも、例外の構築が終了してからスローされます)。これは明らかに、ソースが制御されている例外でのみ機能します。

これはお勧めしません。デバッガーが接続されたデバッグ ビルドでは、例外のスロー時に「最初のチャンス」ブレークを取得することを選択できます。通常はこれで十分です。

もう 1 つのオプションは、例外スロー サイトでプログラムによってミニ ダンプの生成を開始することです。このようなデータは、windbg などのツールを使用して後で検査できますが、スタックをアンワインドする例外の望ましい動作をあまり妨げません。

例外がキャッチオール トラップに到達するという行為は、まさに望んでいないスタックの巻き戻しです。申し訳ありません。C++ に慣れていて、それが好きなら、すべての例外がデバッガーをトリガーする原因となる mono のマイナーな (ただし、正しく行うには複雑な) フォークを作成できます。または、モノの BCL 例外クラスを再構築して、上記と同じことを行います..

于 2009-02-12T00:25:36.983 に答える
1

クラッシュさせてから登録して、Microsoft から Windows エラー レポートを受信して​​みませんか? 詳細については、 http://msdn.microsoft.com/en-us/isv/bb190483.aspxを参照してください。

それをしたくない場合は、IsDebuggerPresent 関数 ( http://msdn.microsoft.com/en-us/library/ms680345.aspx ) を使用できます。結果が False の場合は、コードをラップする代わりにtry-catch で、イベント ハンドラーを AppDomain.UnhandledException イベント ( http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx )に追加します。

于 2009-02-12T03:28:59.023 に答える
0

グローバルイベントのいずれもうまくいかない場合は、ソフトウェアが処理するイベントにエラーキャッチを入れることを試みることができます。これらの容易さは、アプリケーションの複雑さに依存します。.NET Frameworkで記述されたアプリケーションの多くは、従来のアプリケーションであろうとWebアプリケーションであろうと、イベントを処理するために記述されています。イベント自体にフックを配置することで、必要なスタック内の情報を保持できるはずです。

于 2009-02-13T14:12:43.383 に答える
0

開発にデバッグ モードを使用し、デプロイにリリース モードを厳密に使用している場合は、System.Diagnostics.Debugger クラスを使用してみることができます。

catch (Exception e) {
#if DEBUG
            System.Diagnostics.Debugger.Launch()
#endif
            LogException(e);
            throw;
        }
于 2008-10-17T12:00:33.220 に答える
0

トレース ログに書き込むことで、例外の情報を取得できます。

        private static void Main(string[] args)
    {
        try
        {
            // ...
        }
        catch (Exception exception)
        {
            System.Diagnostics.Trace.Write(exception);
            #if DEBUG
            System.Diagnostics.Trace.Write("Waiting 20 seconds for debuggers to attach to process.");
            System.Threading.Thread.Sleep(20000);
            System.Diagnostics.Trace.Write("Continue with process...");
            #endif
            throw;
        }
    }

DebugViewを使用して、トレース ログを表示します。スレッドを数秒間停止すると、元の例外を失うことなく、デバッガーをプロセスにアタッチする時間が得られます。

于 2009-02-11T10:14:48.573 に答える
0

単純にすべきではありません

Exception e1 = e;
LogException(e);
throw(e1);

キャッチ内でトリックを行いますか(少なくとも外側の例外を調べることができます)?

于 2008-10-17T10:17:16.347 に答える