C#怎么捕获全局异常 C# AppDomain.CurrentDomain.UnhandledException处理方法

来源:这里教程网 时间:2026-02-21 17:38:27 作者:

在 C# 中捕获全局未处理异常,主要靠

AppDomain.CurrentDomain.UnhandledException
事件,但它**只适用于非 UI 线程和主线程中未被 try-catch 捕获的异常**,且**无法阻止程序退出**(仅能记录日志、做善后)。它不是“万能兜底”,尤其对 WinForms/WPF 的 UI 线程异常需配合其他机制。

AppDomain.UnhandledException 基本用法

该事件在异常未被任何 catch 捕获、即将导致进程终止前触发。注册一次即可,通常放在

Main()
开头或应用启动处:

示例:

static void Main(string[] args)
{
    AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
    {
        var ex = e.ExceptionObject as Exception;
        Console.WriteLine($"全局异常:{ex?.Message}");
        // 记录日志、保存状态、弹提示(谨慎)、发送告警等
        // ⚠️ 注意:e.IsTerminating 为 true,此时不应调用复杂逻辑或 UI 操作
    };
<pre class="brush:php;toolbar:false;">// 启动你的主逻辑
Application.Run(new MainForm()); // WinForms 示例

}

它不能捕获哪些异常?

以下情况 不会触发 此事件:

UI 线程中抛出的异常(如 WinForms 的 Button.Click 内未捕获异常)——这类由 Windows 消息循环拦截,需用
Application.ThreadException
(WinForms)或
DispatcherUnhandledException
(WPF)
Task 异常未 await 或未 .Wait()/.Result —— 默认不传播到主线程,需监听
TaskScheduler.UnobservedTaskException
已用 try-catch 捕获并吞掉的异常 StackOverflowException、OutOfMemoryException(部分情况下)等严重运行时异常

WinForms / WPF 必须补充的监听

为了真正“全局”,必须组合使用:

WinForms:注册
Application.ThreadException
处理 UI 线程异常
WPF:在 App.xaml.cs 中订阅
Application.DispatcherUnhandledException
所有托管线程:加上
TaskScheduler.UnobservedTaskException
防止遗漏异步异常

WinForms 完整示例片段:

static void Main()
{
    // 1. UI 线程异常(关键!)
    Application.ThreadException += (s, e) =>
    {
        LogError("UI线程异常", e.Exception);
        MessageBox.Show("发生错误,请重启应用。");
    };
<pre class="brush:php;toolbar:false;">// 2. 其他线程 + 主线程非 UI 异常
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
{
    LogError("未处理异常", e.ExceptionObject as Exception);
};
// 3. 异步任务异常(未观察到的)
TaskScheduler.UnobservedTaskException += (s, e) =>
{
    e.SetObserved(); // 标记为已处理,避免后续终止
    LogError("未观察到的任务异常", e.Exception);
};
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());

}

注意事项与最佳实践

这些事件是“最后机会”,但有严格限制:

不要在其中执行耗时操作(如写大文件、网络请求)——进程可能随时终止 避免调用 UI 控件(如 MessageBox 在非 UI 线程弹窗会失败),如需提示,用
BeginInvoke
或检查线程上下文
记录日志建议用轻量方式(如写入本地文本、EventLog),并确保路径可写
e.IsTerminating
为 true 时,禁止 throw 新异常或调用 Environment.Exit()
.NET Core/.NET 5+ 中
AppDomain
已弱化,推荐优先用
HostBuilder
UseExceptionHandler
(ASP.NET)或
Try-Catch in Main
+ 全局日志中间件

基本上就这些。AppDomain.UnhandledException 是重要一环,但不是全部——搭配 ThreadException、DispatcherUnhandledException 和 TaskScheduler 三者,才能覆盖绝大多数托管异常场景。

相关推荐