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

首先使用方法而不是委托,因此方法名称将被定义

然后使用 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
}

我认为上面的方法不起作用,因为它总是包含方法名称,但是如果它出现超过 1 次,你可以计算。另外,在发布模式下编译时检查它是否没有内联,在这种情况下你有麻烦了

于 2012-05-22T07:11:17.457 回答
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 回答
-2

一般来说,您可以像处理所有其他异常一样处理异常,但特别是异常呢StackOverflowOutOfMemory它们无法在 .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 回答