簡體   English   中英

可以C#WinForm靜態void主要不捕獲異常嗎?

[英]Can C# WinForm static void Main NOT catching Exception?

我有一個用C#編寫的WinForm應用程序,我在Program.cs ,在程序入口中放置一個try-catch塊, 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-catchtry-catch並存儲在錯誤日志文件中。

但是,當我運行我的程序一段時間后,我得到一個未處理的異常( null引用)。 讓我感到驚訝的是,異常不會創建錯誤日志文件。

現在, 這篇文章顯示它可能是由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

那為什么會這樣?

try-catch塊應捕獲最后一個Exception

這不會發生。 除了一種情況,當您運行附帶調試器的程序時。 所以你肯定會相信它會起作用,每個人總是開始用F5運行他們的程序一段時間。

Application.Run()在其代碼中有一個反向停止引發事件,try / catch-em-all在事件處理程序拋出未處理的異常時引發Application.ThreadException事件。 這回站是真的, 真的有必要,特別是在Windows x64版本7 非常不好的事情發生時,有沒有異常處理程序。 但是,當您使用調試器運行時,該后退不會到位,這使得未處理的異常難以調試。

因此,當您調試時,您的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但是注意到這個bug目前在Windows 10上又回來了。嘆了口氣。

ThreadException不是類似( NullReferenceException )的異常類型。 就是它:

此事件允許Windows窗體應用程序處理Windows窗體線程中出現的其他未處理的異常

這意味着它處理主線程以外的線程中的異常。

因此,您還需要訂閱: AppDomain.CurrentDomain.UnhandledException ,以便處理主線程中的異常(無論異常的類型如NullReferenceIndexOutOfRange等等)。

好的,最后我在本文中Hans PassantVB.Net實現了Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException) 在這里,我為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 ... 

第二個發生在Form組件的Dispose期間,它創建了另一個異常,它是null引用異常:

 System.NullReferenceException: Object reference not set to an instance of an object. at T5ShortestTime.T5ShortestTimeForm.Dispose(Boolean disposing) at System.ComponentModel.Component.Finalize() 

所以,當我在我的應用程序中測試異常時, NullReferenceExceptionDispose的最后一個。

在此輸入圖像描述

在上面將UnhandledExceptionMode設置為ThrowException之后,我才設法捕獲它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM