我正在使用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.");
}
答案 0 :(得分:9)
这对我有用:
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;
}
}
答案 1 :(得分:1)
虽然这不是一个好方法,但是在VB .NET中,您可以使用“On Error Resume Next”语句来防止在FirstChanceException事件处理程序中触发异常,来自VB 6.(我不确定C#是否有类似的东西)另外,你应该像前面提到的here一样阻止对事件处理程序的递归。以下是示例代码,似乎按预期工作。
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
答案 2 :(得分:0)
您链接的MSDN文章提出了一些建议:
您必须处理FirstChanceException事件的事件处理程序中发生的所有异常。否则,递归引发FirstChanceException。这可能导致堆栈溢出和应用程序终止。我们建议您将此事件的事件处理程序实现为受约束的执行区域(CER),以便在处理异常通知时保持与内存相关的异常(例如内存不足或堆栈溢出)不会影响虚拟机。
所以将你的函数包含在try / catch块中,并在块之前调用PrepareConstrainedRegion
以避免OutOfMemory异常:http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx
编辑:嗯,即使使用try / catch块,你仍然会遇到递归问题。所以...我想你只需要调用不会抛出任何异常的安全代码。该事件处理程序似乎非常危险,我建议仅将其用于调试目的。
答案 3 :(得分:0)
首先使用方法而不是委托,因此将定义方法名称
然后使用Environment.StackTrace检查该方法是否已经在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次,则可以计算。 另外,在Release模式下编译时检查它是否没有内联,在这种情况下你遇到了麻烦
答案 4 :(得分:-1)
一般情况下,您可以像处理所有其他异常一样处理异常,但在特定的StackOverflow
和OutOfMemory
异常中,它们无法在.NET Framework中处理。
请看这里:How do I prevent and/or handle a StackOverflowException? (C#)
从.NET Framework 2.0版开始,发生StackOverflowException 对象不能被try-catch块和相应的块捕获 进程默认终止。因此,建议用户 编写代码来检测并防止堆栈溢出。例如, 如果您的应用程序依赖于递归,请使用计数器或状态 条件终止递归循环。
答案 5 :(得分:-1)
我认为在异常处理程序中添加另一个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.");
}
答案 6 :(得分:-1)
手动处理例外情况,例如
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.");
}