在 Avalonia 中实现全局异常处理器,核心是捕获应用主线程未处理的异常(如 UI 线程中抛出但未被 try/catch 捕获的异常),以及任务异步操作中未观察到的异常。Avalonia 本身基于 .NET 运行时,因此需结合 .NET 的异常捕获机制,并在 Avalonia 生命周期关键节点进行注册。
监听 AppDomain.CurrentDomain.UnhandledException
这是捕获非托管线程或部分同步上下文中未处理异常的兜底方式,适用于大多数崩溃性异常(如 NullReferenceException 在事件处理中直接抛出)。
在 App.xaml.cs 的 App() 构造函数或 App.Initialize() 之前 就注册,确保尽早生效 该事件无法阻止应用退出,但可用于日志记录、弹窗提示或数据保存 注意:它不捕获 async void 方法中的异常,也不捕获 Task 异常(除非未 await 且未被 TaskScheduler.UnobservedTaskException 捕获)订阅 TaskScheduler.UnobservedTaskException
用于捕获被丢弃(未 await、未 .Wait()、未 .Result)的 Task 中抛出的异常。这类异常默认会被静默吞掉,直到 GC 时触发此事件。
建议在应用启动早期(如 App.OnFrameworkInitializationCompleted 或 Program.BuildAvaloniaApp().StartWithClassicDesktopLifetime() 之后)注册 调用e.SetObserved()可标记为“已处理”,避免最终触发 AppDomain.UnhandledException 典型场景:忘记 await 一个命令执行、后台 Task.Run 内部出错但没处理
重写 Application.OnUnhandledException(Avalonia 11+ 推荐)
Avalonia 11 起提供了更贴近框架语义的入口:
Application.OnUnhandledException,它会在 Avalonia 内部检测到 UI 线程未处理异常(如路由事件处理器、绑定转换器、控件生命周期方法中抛异常)时被调用。 继承自 Application 类,在其中重写该方法
OnUnhandledException传入的
UnhandledExceptionEventArgs包含
Exception和
Handled属性 设置
e.Handled = true可阻止 Avalonia 默认的崩溃行为(如弹出错误对话框),自行处理(如显示友好提示、上报) 注意:它不替代 AppDomain 或 TaskScheduler 的监听,而是补充 Avalonia 特定上下文
可选:包装 Dispatcher.UIThread.Post/Invoke 操作
对于手动调度到 UI 线程的代码(如
Dispatcher.UIThread.InvokeAsync(() => { ... })),异常不会自动冒泡到全局处理器。可封装一层安全调用:
定义扩展方法如 SafeInvokeAsync(this IDispatcher dispatcher, Action action)内部用 try/catch 包裹并转发到全局日志或提示系统 适合对关键 UI 更新逻辑做防御性增强,非必须但能提升健壮性
基本上就这些。三者配合使用(AppDomain + TaskScheduler + OnUnhandledException)可覆盖绝大多数未处理异常场景。不需要第三方库,纯 Avalonia + .NET 原生机制即可实现可靠捕获。
