控制台应用程序中的.NET Global异常处理程

Ste*_*ger 189 .net c# vb.net exception-handling console-application

问题:我想在控制台应用程序中为未处理的异常定义一个全局异常处理程序.在asp.net中,可以在global.asax中定义一个,在windows应用程序/服务中,可以定义如下

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
Run Code Online (Sandbox Code Playgroud)

但是,如何为控制台应用程序定义全局异常处理程序?
currentDomain似乎不起作用(.NET 2.0)?

编辑:

唉,愚蠢的错误.
在VB.NET中,需要在currentDomain前添加"AddHandler"关键字,否则在IntelliSense中看不到UnhandledException事件......
这是因为VB.NET和C#编译器对事件处理的处理方式不同.

Han*_*ant 272

不,这是正确的方法.这完全可以正常工作,你可以从中工作:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

请记住,您无法通过这种方式捕获由抖动生成的类型和文件加载异常.它们发生在Main()方法开始运行之前.捕获这些需要延迟抖动,将危险代码移动到另一个方法并将[MethodImpl(MethodImplOptions.NoInlining)]属性应用于它.

  • 它肯定会!我们在这里不是在谈论Application.ThreadException事件. (6认同)
  • 我认为理解这个答案和回复中的注释的关键是要意识到这个代码现在演示了检测异常,但没有像在正常的try/catch块中那样完全"处理"它,你可以选择继续.请参阅我的其他答案了解详情.如果以这种方式"处理"异常,则在另一个线程上发生异常时,您无法继续运行.从这个意义上说,如果用"句柄"表示"处理并继续运行",可以说这个答案没有完全"处理"异常. (4认同)
  • 更不用说有很多技术可以在不同的线程中运行.例如,任务并行库(TPL)有自己的方法来捕获未处理的异常.所以,他说,这并不适用于所有情况是怎么样的荒唐可笑的,没有一个地方捕获所有在C#中的一切,但是这取决于你使用的还有你可以连接到各个地方的技术. (4认同)
  • 我实现了你在这里提出的建议,但我不想退出应用程序.我只是想记录它,并继续这个过程(没有`Console.ReadLine()`或任何其他程序流程的干扰.但我得到的是一次又一次地重新提升异常. (3认同)
  • @Shahrooz Jefri:一旦遇到未处理的异常,您将无法继续。堆栈被弄乱了,这是终端。如果您有服务器,则在UnhandledExceptionTrapper中可以执行的操作是使用相同的命令行参数重新启动程序。 (2认同)

Blu*_*kMN 23

如果你有一个单线程应用程序,你可以在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;
   }
}
Run Code Online (Sandbox Code Playgroud)

您可以在应用程序退出之前接收另一个线程何时抛出异常以执行某些清理的通知,但据我所知,如果您不处理异常,则无法从控制台应用程序强制应用程序继续运行在没有使用一些模糊的兼容性选项的情况下抛出它的线程,使应用程序的行为与.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;
   }
}
Run Code Online (Sandbox Code Playgroud)

所以在我看来,在控制台应用程序中处理它的最简单方法是确保每个线程在根级别都有一个异常处理程序:

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");
   }
}
Run Code Online (Sandbox Code Playgroud)

  • @ChrisKuliukas 例外情况没有被抑制。它们正在输出到控制台。与应用程序在未处理异常的情况下退出相比,您更有可能以这种方式看到它。 (2认同)

Bla*_*ICE 12

您还需要处理线程中的异常:

static void Main(string[] args) {
Application.ThreadException += MYThreadHandler;
}

private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
{
    Console.WriteLine(e.Exception.StackTrace);
}
Run Code Online (Sandbox Code Playgroud)

哎呀,抱歉是winforms,对于你在控制台应用程序中使用的任何线程,你必须将它们包含在try/catch块中.遇到未处理异常的后台线程不会导致应用程序结束.