问:我想在我的控制台应用程序中为未处理的异常定义一个全局异常处理程序。在asp.net中,可以在global.asax中定义一个,在windows应用程序/服务中,可以定义如下
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
但是如何为控制台应用程序定义全局异常处理程序?
currentDomain 似乎不起作用(.NET 2.0)?
编辑:
啊,愚蠢的错误。
在VB.NET中,需要在currentDomain前面加上“AddHandler”关键字,否则在IntelliSense中看不到UnhandledException事件…
这是因为 VB.NET 和 C# 编译器对事件处理的处理方式不同。
如果您有一个单线程应用程序,您可以在 Main 函数中使用简单的 try/catch,但是,这不包括可能在 Main 函数之外引发的异常,例如在其他线程上(如其他线程中所述)注释)。此代码演示了即使您尝试在 Main 中处理异常,异常如何导致应用程序终止(请注意,如果您按 Enter 并允许应用程序在异常发生之前正常退出,但如果您让它运行,程序将如何正常退出,它非常不愉快地终止):
static bool exiting = false;
static void Main(string[] args)
{
try
{
System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
demo.Start();
Console.ReadLine();
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception");
}
}
static void DemoThread()
{
for(int i = 5; i >= 0; i--)
{
Console.Write("24/{0} =", i);
Console.Out.Flush();
Console.WriteLine("{0}", 24 / i);
System.Threading.Thread.Sleep(1000);
if (exiting) return;
}
}
您可以收到另一个线程何时抛出异常以在应用程序退出之前执行一些清理的通知,但据我所知,如果您不处理异常,您不能从控制台应用程序强制应用程序继续运行在抛出它的线程上,不使用一些晦涩的兼容性选项来使应用程序的行为与 .NET 1.x 一样。这段代码演示了如何通知主线程来自其他线程的异常,但仍会不愉快地终止:
static bool exiting = false;
static void Main(string[] args)
{
try
{
System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
demo.Start();
Console.ReadLine();
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("Notified of a thread exception... application is terminating.");
}
static void DemoThread()
{
for(int i = 5; i >= 0; i--)
{
Console.Write("24/{0} =", i);
Console.Out.Flush();
Console.WriteLine("{0}", 24 / i);
System.Threading.Thread.Sleep(1000);
if (exiting) return;
}
}
所以在我看来,最干净的处理方式在控制台应用程序中是确保每个线程在根级别都有一个异常处理程序:
static bool exiting = false;
static void Main(string[] args)
{
try
{
System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
demo.Start();
Console.ReadLine();
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception");
}
}
static void DemoThread()
{
try
{
for (int i = 5; i >= 0; i--)
{
Console.Write("24/{0} =", i);
Console.Out.Flush();
Console.WriteLine("{0}", 24 / i);
System.Threading.Thread.Sleep(1000);
if (exiting) return;
}
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception on the other thread");
}
}
TRY CATCH 在发布模式下因意外错误不起作用:/
啊,当然,这真的很糟糕。。迟早你的应用程序会在线程中引入一个错误,它会在中途停止然后默默退出,你会认为它完全工作,你会在记住你愚蠢地压制了所有例外之前,花很长时间试图弄清楚它。
您还需要处理来自线程的异常:
static void Main(string[] args) {
Application.ThreadException += MYThreadHandler;
}
private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
{
Console.WriteLine(e.Exception.StackTrace);
}
哎呀,对不起,这是针对 winforms 的,对于您在控制台应用程序中使用的任何线程,您都必须将其包含在 try/catch 块中。遇到未处理异常的后台线程不会导致应用程序结束。
我刚刚继承了一个旧的 VB.NET 控制台应用程序,需要设置一个全局异常处理程序。由于这个问题多次提到 VB.NET 并被标记为 VB.NET,但这里的所有其他答案都在 C# 中,我想我也会为 VB.NET 应用程序添加确切的语法。
Public Sub Main()
REM Set up Global Unhandled Exception Handler.
AddHandler System.AppDomain.CurrentDomain.UnhandledException, AddressOf MyUnhandledExceptionEvent
REM Do other stuff
End Sub
Public Sub MyUnhandledExceptionEvent(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
REM Log Exception here and do whatever else is needed
End Sub
我用REM
注释标记而不是这里的单引号,因为 Stack Overflow 似乎可以更好地处理语法突出显示REM
.