[英]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-catch
塊try-catch
並存儲在錯誤日志文件中。
但是,當我運行我的程序一段時間后,我得到一個未處理的異常( null
引用)。 讓我感到驚訝的是,異常不會創建錯誤日志文件。
現在, 這篇文章顯示它可能是由ThreadException
或HandleProcessCorruptedStateExceptions
(兩個最受歡迎的答案)引起的,但是我的案例顯示了一個簡單的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 ,以便處理主線程中的異常(無論異常的類型如NullReference
, IndexOutOfRange
等等)。
好的,最后我在本文中以Hans Passant為VB.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()
所以,當我在我的應用程序中測試異常時, NullReferenceException
是Dispose
的最后一個。
在上面將UnhandledExceptionMode
設置為ThrowException
之后,我才設法捕獲它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.