问题:我想为控制台应用程序中未处理的异常定义一个全局异常处理程序。在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# 编译器对待事件处理的方式不同。
不,这是正确的做法。这完全按照它应该的方式工作,也许你可以从中工作:
using System;
class Program {
static void Main(string[] args) {
System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
throw new Exception("Kaboom");
}
static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) {
Console.WriteLine(e.ExceptionObject.ToString());
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
Environment.Exit(1);
}
}
请记住,您无法通过这种方式捕获抖动生成的类型和文件加载异常。它们发生在您的
Main()
方法开始运行之前。捕获这些需要延迟抖动,将有风险的代码移至另一个方法中,并对其应用 [MethodImpl(MethodImplOptions.NoInlining)]
属性。
如果您有一个单线程应用程序,则可以在 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");
}
}
您还需要处理线程的异常:
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
可以更好地处理语法突出显示。
您正在尝试的内容应该根据 .Net 2.0 的 MSDN 文档工作。您还可以在控制台应用程序的入口点周围尝试在 main 中尝试/catch。
static void Main(string[] args)
{
try
{
// Start Working
}
catch (Exception ex)
{
// Output/Log Exception
}
finally
{
// Clean Up If Needed
}
}
现在你的 catch 将处理任何未捕获的内容(在主线程中)。它可以很优雅,甚至可以在您愿意的情况下重新启动,或者您可以让应用程序终止并记录异常。如果你想进行任何清理,你可以添加一个finally。 每个线程都需要自己的高级异常处理,类似于主线程。
编辑以澄清 BlueMonkMN 指出的有关线程的观点,并在他的答案中详细显示。