19

スローされた例外に関する詳細をログに記録するために、 FirstChanceExceptionイベントを使用しています。

static void Main(string[] args)
{
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
    {
        Console.WriteLine("Inside first chance exception.");
    };

    throw new Exception("Exception thrown in main.");
}

これは期待どおりに機能します。ただし、イベント ハンドラー内で例外がスローされると、イベントが再帰的に発生するため、スタック オーバーフローが発生します。

static void Main(string[] args)
{
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
    {
        throw new Exception("Stackoverflow");
    };

    throw new Exception("Exception thrown in main.");
}

イベント ハンドラー内で発生する例外を処理するにはどうすればよいですか?

編集:

イベントハンドラー内のコードをtry/catchブロックでラップすることを示唆するいくつかの回答がありますが、例外が処理される前にイベントが発生するため、これは機能しません。

static void Main(string[] args)
{
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
    {
        try
        {
            throw new Exception("Stackoverflow");
        }
        catch
        {
        }
    };

    throw new Exception("Exception thrown in main.");
}
4

7 に答える 7

18

これは私のために働いています:

private volatile bool _insideFirstChanceExceptionHandler;    

// ...

AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;

// ...

private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs args)
{
    if (_insideFirstChanceExceptionHandler)
    {
        // Prevent recursion if an exception is thrown inside this method
        return;
    }

    _insideFirstChanceExceptionHandler = true;
    try
    {
        // Code which may throw an exception
    }
    catch
    {
        // You have to catch all exceptions inside this method
    }
    finally
    {
        _insideFirstChanceExceptionHandler = false;
    }
}
于 2015-10-15T16:38:23.947 に答える
1

良い方法ではありませんが、VB .NET では、VB 6 に由来する "On Error Resume Next" ステートメントを使用して、FirstChanceException イベント ハンドラー内で例外が発生するのを防ぐことができます (C# に同様の機能があるかどうかはわかりません)。ここで述べたように、イベント ハンドラーでの再帰を防ぎます。以下はサンプルコードで、期待どおりに動作するようです。

Sub Main(args As String())
    AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceExceptionEventHandler
    Throw New Exception("Exception thrown in main.")
End Sub

Private Sub FirstChanceExceptionEventHandler(ByVal source As Object, ByVal e As FirstChanceExceptionEventArgs)
    On Error Resume Next

    Dim frames As StackFrame() = New StackTrace(1).GetFrames()
    Dim currentMethod As MethodBase = MethodBase.GetCurrentMethod()
    If frames IsNot Nothing AndAlso frames.Any(Function(x) x.GetMethod() = currentMethod) Then
        Return
    Else
        Throw New Exception("Stackoverflow")
    End If
End Sub
于 2014-06-27T07:37:44.533 に答える
0

リンクしたMSDNの記事には、いくつかの推奨事項があります。

FirstChanceExceptionイベントのイベントハンドラーで発生するすべての例外を処理する必要があります。それ以外の場合、FirstChanceExceptionは再帰的に発生します。これにより、スタックオーバーフローが発生し、アプリケーションが終了する可能性があります。このイベントのイベントハンドラーを制約付き実行領域(CER)として実装し、例外通知の処理中にメモリ不足やスタックオーバーフローなどのインフラストラクチャ関連の例外が仮想マシンに影響を与えないようにすることをお勧めします。

したがって、関数をtry / catchブロック内に囲み、PrepareConstrainedRegionブロックの前に呼び出してOutOfMemory例外を回避します。http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

編集:まあ、try/catchブロックでも再帰の問題があります。だから...私はあなたが例外をスローしない安全なコードだけを呼び出す必要があると思います。そのイベントハンドラーは非常に危険なようです。デバッグ目的でのみ使用することをお勧めします。

于 2012-05-22T07:00:47.040 に答える
0

最初にデリゲートの代わりにメソッドを使用するので、メソッド名が定義されます

次に、Environment.StackTraceを使用して、メソッドがすでにスタックトレースにあるかどうかを確認します

これがテストされていないコードの一部です:

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += handleFirstChanceException;
} 

private void handleFirstChanceException(object sender, EventArgs eventArgs)
{
    if (Environment.StackTrace.Contains("handleFirstChanceException"))
        return;

    // handle
}

上記は常にメソッド名が含まれているため機能しないと思いますが、複数回出現する場合はカウントできます。また、リリースモードでコンパイルするときにインライン化されていないことを確認してください。この場合、問題が発生します。

于 2012-05-22T07:11:17.457 に答える
-2

StackOverflow一般的な例外では、他のすべての例外と同様に処理できますが、特にOutOfMemory例外については、.NET Framework では処理できません。

こちらをご覧ください: StackOverflowException を防止および/または処理するにはどうすればよいですか? (C#)

.NET Framework バージョン 2.0 以降では、StackOverflowException オブジェクトを try-catch ブロックでキャッチできず、対応するプロセスが既定で終了します。したがって、スタック オーバーフローを検出して防止するコードを記述することをお勧めします。たとえば、アプリケーションが再帰に依存している場合は、カウンターまたは状態条件を使用して再帰ループを終了します。

于 2012-05-22T06:52:02.523 に答える
-3

try {} catch (){}例外ハンドラーに別のブロックを追加すると役立つと思います

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
        try {
            throw new Exception("Stackoverflow"); 
        } catch (Exception e)
        {
           // Do something very simple not throwing an exception...
        }
    }; 

    throw new Exception("Exception thrown in main."); 
} 
于 2012-05-22T06:55:27.433 に答える
-3

内部例外を手動で処理します。例:

static void Main(string[] args) {
     AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
     {
         try{
         throw new Exception("Stackoverflow");} catch (Exception ex){/*manual handle*/}
     };
      throw new Exception("Exception thrown in main.");
 } 
于 2012-05-22T06:56:34.240 に答える