Может ли C# WinForm статическая пустота Main НЕ перехватить исключение?
У меня есть 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
ссылка). Что меня удивляет, так это то, что исключение не создает файл журнала ошибок.
Теперь этот пост показывает, что это может быть вызвано 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
С чего бы это?
3 ответа
последнее исключение должно быть зафиксировано блоком try-catch
Этого не произойдет. За исключением одного случая, когда вы запускаете вашу программу с подключенным отладчиком. Таким образом, вы наверняка успокоились, полагая, что это сработает, каждый всегда начинает какое-то время запускать свою программу с F5.
Application.Run() имеет в своем коде back-stop, который вызывает события, try/catch-em-all, который вызывает событие Application.ThreadException, когда обработчик события генерирует необработанное исключение. Такая задержка действительно необходима, особенно в 64-разрядной версии Windows 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, но заметил, что эта ошибка снова возвращается в Windows 10. Вздох.
ThreadException
не является типом исключения типа (NullReferenceException
). Это то, что:
Это событие позволяет приложению Windows Forms обрабатывать необработанные исключения, возникающие в потоках Windows Forms.
Это означает, что он обрабатывает исключения в потоках, отличных от основного потока.
Итак, вам необходимо подписаться на: AppDomain.CurrentDomain.UnhandledException также для обработки исключений в вашем основном потоке (независимо от типа исключения, например NullReference
, IndexOutOfRange
, так далее..).
Хорошо, в конце концов, я реализую Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
например, Hans Passant для 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
в ThrowException
выше.