提问人:Stefan Steiger 提问时间:6/28/2010 最后编辑:spinodalStefan Steiger 更新时间:6/20/2020 访问量:117915
控制台应用程序中的 .NET 全局异常处理程序
.NET Global exception handler in console application
问:
问:我想在控制台应用程序中为未处理的异常定义全局异常处理程序。在 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)] 属性应用于它。
评论
Console.ReadLine()
您正在尝试的操作应根据 .Net 2.0 的 MSDN 文档进行。还可以在控制台应用入口点附近的 main 中尝试 try/catch。
static void Main(string[] args)
{
try
{
// Start Working
}
catch (Exception ex)
{
// Output/Log Exception
}
finally
{
// Clean Up If Needed
}
}
现在你的捕获将处理任何未捕获的内容(在主线程中)。它可以是优雅的,甚至可以根据需要在原来的位置重新启动,或者您可以让应用程序死亡并记录异常。如果你想做任何清理,你可以添加一个最后。每个线程都需要自己的高级异常处理,类似于 main。
编辑以澄清 BlueMonkMN 指出的有关线程的观点,并在他的回答中详细显示。
评论
您还需要处理来自线程的异常:
static void Main(string[] args) {
Application.ThreadException += MYThreadHandler;
}
private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
{
Console.WriteLine(e.Exception.StackTrace);
}
哎呀,对不起,这是针对 winforms,对于您在控制台应用程序中使用的任何线程,您都必须包含在 try/catch 块中。遇到未经处理的异常的后台线程不会导致应用程序结束。
如果您有一个单线程应用程序,则可以在 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");
}
}
评论
我刚刚继承了一个旧的 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
我在这里使用了注释标记而不是单引号,因为 Stack Overflow 似乎可以更好地处理语法突出显示。REM
REM
评论