可以C#WinForm静态void主要不捕获异常吗?

时间:2016-05-25 05:07:23

标签: c# winforms exception

我有一个用WinForm编写的C#应用程序,我在try-catch中的Program.cs块,在程序条目中static void Main方法,就像这样在应用程序的开头:

using System;
using System.IO;
using System.Windows.Forms;

namespace T5ShortestTime {
    static class Program {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
            try {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new T5ShortestTimeForm());
            } catch (Exception e) {
                string errordir = Path.Combine(Application.StartupPath, "errorlog");
                string errorlog = Path.Combine(errordir, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".txt");
                if (!Directory.Exists(errordir))
                    Directory.CreateDirectory(errordir);                
                File.WriteAllText(errorlog, e.ToString());              
            }
        }
    }
}

如您所见,Application放在try-catch块中,在catch块中,它唯一能做的就是创建错误日志文件。

现在,到目前为止一切顺利。我的应用程序运行良好,如果遇到崩溃,Exception块应捕获最后try-catch并存储在错误日志文件中。

然而,当我运行我的程序一段时间后,我得到一个未处理的异常(null引用)。令我感到惊讶的是,异常不会创建错误日志文件。

现在,this post显示它可能是由ThreadExceptionHandleProcessCorruptedStateExceptions(两个最受欢迎的答案)引起的,但我的案例显示了一个简单的null引用异常:

Problem signature:
  Problem Event Name:   CLR20r3
  Problem Signature 01: T5ShortestTime.exe
  Problem Signature 02: 2.8.3.1
  Problem Signature 03: 5743e646
  Problem Signature 04: T5ShortestTime
  Problem Signature 05: 2.8.3.1
  Problem Signature 06: 5743e646
  Problem Signature 07: 182
  Problem Signature 08: 1b
  Problem Signature 09: System.NullReferenceException
  OS Version:   6.3.9600.2.0.0.272.7
  Locale ID:    1033
  Additional Information 1: bb91
  Additional Information 2: bb91a371df830534902ec94577ebb4a3
  Additional Information 3: aba1
  Additional Information 4: aba1ed7202d796d19b974eec93d89ec2

Read our privacy statement online:
  http://go.microsoft.com/fwlink/?linkid=280262

If the online privacy statement is not available, please read our privacy statement offline:
  C:\Windows\system32\en-US\erofflps.txt

为什么会这样?

3 个答案:

答案 0 :(得分:5)

  

最后一个Exception应该被try-catch块

捕获

这不会发生。除了一种情况,当您运行附带调试器的程序时。所以你肯定会觉得它会起作用,每个人总是开始用F5运行他们的程序一段时间。

Application.Run()在其代码中有一个反向停止引发事件,try / catch-em-all在事件处理程序抛出未处理的异常时引发Application.ThreadException事件。实际上,确实是非常必要的,尤其是在没有异常处理程序的Windows 7的x64版本上。ExecutorService Examples。但是,当您使用调试器运行时,这种后退不存在,这使得未处理的异常难以调试。

因此,当您进行调试时,您的 catch 子句将会运行。使未处理的异常太难以调试。当你在没有调试器的情况下运行时,你的catch子句将运行,你的程序将崩溃,正如你所描述的那样。使未处理的异常难以调试。

所以不要这样做。 Application.Run()如何处理未处理的异常是使用Application.SetUnhandledExceptionMode()方法配置的。你会更喜欢这个版本:

    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        if (!System.Diagnostics.Debugger.IsAttached) {
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
            AppDomain.CurrentDomain.UnhandledException += LogException;
        }
        Application.Run(new Form1());
    }

    private static void LogException(object sender, UnhandledExceptionEventArgs e) {
        string errordir = Path.Combine(Application.StartupPath, "errorlog");
        string errorlog = Path.Combine(errordir, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".txt");
        if (!Directory.Exists(errordir))
            Directory.CreateDirectory(errordir);
        File.WriteAllText(errorlog, e.ToString());
        AppDomain.CurrentDomain.UnhandledException -= LogException;
        MessageBox.Show("Error details recorded in " + errorlog, "Unexpected error");
        Environment.Exit(1);
    }

使用此代码,您可以毫无问题地调试未处理的异常。 Debugger.IsAttached测试确保调试器在事件处理程序崩溃时始终停止。如果没有调试器,它会禁用Application.ThreadException事件(它没用)并且倾向于收听所有异常。包括在工作线程中引发的那些。

你应该向用户发出警告,这样窗口就不会消失而没有任何痕迹。我打算推荐MessageBox,但注意到{10}目前在Windows 10上又回来了。叹气。

答案 1 :(得分:2)

ThreadException不是类似(NullReferenceException)的异常类型。就是这样:

  

此事件允许您的Windows窗体应用程序以其他方式处理   Windows窗体线程中出现未处理的异常

这意味着它处理主线程以外的线程中的异常。

因此,您还需要订阅:AppDomain.CurrentDomain.UnhandledException以便处理主线程中的异常(无论异常的类型如何NullReferenceIndexOutOfRange等。 )。

答案 2 :(得分:2)

好的,最后我在Hans PassantApplication.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)VB.Net实施了C#。在这里,我为static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); if (!System.Diagnostics.Debugger.IsAttached) { Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); AppDomain.CurrentDomain.UnhandledException += LogUnhandledExceptions; } Application.Run(new T5ShortestTimeForm()); } private static void LogUnhandledExceptions(object sender, UnhandledExceptionEventArgs e) { Exception ex = (Exception)e.ExceptionObject; string errordir = Path.Combine(Application.StartupPath, "errorlog"); string errorlog = Path.Combine(errordir, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".txt"); if (!Directory.Exists(errordir)) Directory.CreateDirectory(errordir); File.WriteAllText(errorlog, ex.ToString()); Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(ex)); } 添加了自己的代码+错误记录:

Exceptions

此外,这里似乎混淆的原因是实际上发生了两个传播System.Exception: Exception of type 'System.Exception' was thrown. at T5ShortestTime.T5ShortestTimeForm..ctor() in C:\Test.cs:line 45 at T5ShortestTime.Program.Main() in C:\Test.cs:line 19 at ...

第一个是应用程序本身的任何异常:

Dispose

第二个发生在Form组件的null期间,这会产生另一个异常,它是System.NullReferenceException: Object reference not set to an instance of an object. at T5ShortestTime.T5ShortestTimeForm.Dispose(Boolean disposing) at System.ComponentModel.Component.Finalize() 引用异常:

NullReferenceException

因此,当我在我的应用中测试异常时,Dispose位于UnhandledExceptionMode的最后一位。

this post

我将ThrowException设置为上面的Expression<Func<T, bool>> 后,我才设法捕捉到这一点。