Home Articles

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

Asked
Viewed 350 times
173

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

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);

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

Edit:

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

4 Answers

  • 248

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

    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)]属性应用于它 .

  • 22

    您正在尝试的应该根据.Net 2.0的MSDN文档工作 . 您还可以在控制台应用程序的入口点周围尝试使用try / catch .

    static void Main(string[] args)
    {
        try
        {
            // Start Working
        }
        catch (Exception ex)
        {
            // Output/Log Exception
        }
        finally
        {
            // Clean Up If Needed
        }
    }
    

    现在你的捕获将处理任何未捕获的东西(在主线程中) . 它可以是优雅的,甚至可以重新启动它,如果你想要的话,或者你可以让应用程序死掉并记录异常 . 如果你想做任何清理,你最后添加一个 . 每个线程都需要自己的高级异常处理,类似于main .

    编辑澄清了BlueMonkMN指出的有关线程的观点,并在他的回答中详细说明 .

  • 10

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

    static void Main(string[] args) {
    Application.ThreadException += MYThreadHandler;
    }
    
    private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
    {
        Console.WriteLine(e.Exception.StackTrace);
    }
    

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

  • -10

    如果你有一个单线程应用程序,你可以在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");
       }
    }
    

Related