boxmoe_header_banner_img

Hello! 欢迎来到悠悠畅享网!

文章导读

C#的全局异常处理是什么?如何实现?


avatar
作者 2025年9月19日 10

c#全局异常处理通过appDomain和TaskScheduler事件捕获未处理异常,前者用于winForms/wpf应用,后者处理异步任务异常,结合日志记录与用户友好提示,确保程序稳定性,且不影响正常性能。

C#的全局异常处理是什么?如何实现?

C#全局异常处理,简单来说,就是为你的程序设置一个“安全网”,当程序在运行时出现未被捕获的异常时,这个“安全网”就会启动,防止程序崩溃,并允许你记录错误信息,甚至尝试恢复。

全局异常处理的核心在于捕获那些未被try-catch块处理的异常。

解决方案

实现C#全局异常处理主要有两种方式:

  1. Application Domain级别的异常处理: 适用于桌面应用程序(WinForms, WPF)。
  2. TaskScheduler级别的异常处理: 适用于异步操作的异常处理。

1. Application Domain级别的异常处理 (WinForms/WPF)

这种方式通过监听

AppDomain.CurrentDomain.UnhandledException

事件来实现。

using System; using System.windows.Forms; // 或者 using System.Windows; 对于WPF  namespace GlobalExceptionHandlerExample {     static class Program     {         [STAThread]         static void Main()         {             // 订阅未处理异常事件             AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;              Application.EnableVisualStyles();             Application.SetCompatibleTextRenderingDefault(false);             Application.Run(new Form1()); // 你的主窗体         }          private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)         {             // 处理未处理的异常             Exception ex = (Exception)e.ExceptionObject;              // 记录日志             Console.WriteLine("全局异常处理: " + ex.Message);             // 或者使用更专业的日志库,如NLog, Serilog              // 显示错误信息给用户 (可选)             MessageBox.Show("程序出现未预料的错误,请查看日志文件。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);              // 决定是否终止程序             // e.IsTerminating = true; // 默认是false,如果设置为true,程序会立即终止         }     } }

重点:

  • Main

    函数中订阅

    AppDomain.CurrentDomain.UnhandledException

    事件。

  • CurrentDomain_UnhandledException

    方法是你的异常处理逻辑。

  • e.ExceptionObject

    包含了异常的详细信息。

  • e.IsTerminating

    决定了程序是否应该终止。通常情况下,不建议直接终止程序,除非你确定程序已经无法恢复。

2. TaskScheduler级别的异常处理 (异步操作)

对于异步操作,未处理的异常可能不会直接触发

AppDomain.CurrentDomain.UnhandledException

。 这时,你需要使用

TaskScheduler.UnobservedTaskException

事件。

C#的全局异常处理是什么?如何实现?

跃问视频

阶跃星辰推出的AI视频生成工具

C#的全局异常处理是什么?如何实现?39

查看详情 C#的全局异常处理是什么?如何实现?

using System; using System.Threading.Tasks;  public class Example {     public static void Main()     {         // 订阅未观察到的Task异常事件         TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;          // 启动一个Task,故意抛出一个异常         Task.Run(() => { throw new Exception("Task中发生的异常!"); });          // 强制垃圾回收,触发UnobservedTaskException事件         GC.Collect();         GC.WaitForPendingFinalizers();          Console.ReadKey();     }      private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)     {         // 处理未观察到的Task异常         Exception ex = e.Exception.InnerException; // 获取实际的异常          Console.WriteLine("Task异常处理: " + ex.Message);          // 标记异常已被处理,防止程序崩溃         e.SetObserved();     } }

重点:

  • TaskScheduler.UnobservedTaskException

    事件在Task的异常未被观察到(例如,未被

    await

    .Result

    访问)且Task被垃圾回收时触发。

  • e.Exception.InnerException

    包含了实际的异常。

  • 必须调用
    e.SetObserved()

    来标记异常已被处理,否则程序仍然可能崩溃。

全局异常处理会影响性能吗?

全局异常处理本身不会显著影响性能,因为它只有在发生未处理的异常时才会被触发。但是,如果在异常处理程序中执行大量的日志记录、资源清理或其他耗时操作,可能会对性能产生一定的影响。因此,建议在全局异常处理程序中尽量减少不必要的计算和I/O操作。

如何在ASP.net Core中实现全局异常处理?

ASP.NET Core 提供了多种处理异常的方式,包括:

  • Exception Filter: 你可以创建一个全局异常过滤器来捕获和处理未处理的异常。
  • Middleware: 你可以创建一个自定义的中间件来捕获和处理异常。
  • UseExceptionHandler: ASP.NET Core 内置的中间件,可以用来处理异常并显示友好的错误页面。

使用Exception Filter的示例:

using microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging;  public class GlobalExceptionFilter : IExceptionFilter {     private readonly ILogger<GlobalExceptionFilter> _logger;      public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)     {         _logger = logger;     }      public void OnException(ExceptionContext context)     {         _logger.LogError(context.Exception, "发生全局异常");          // 可以根据异常类型返回不同的结果         if (context.Exception is ArgumentNullException)         {             context.Result = new BadRequestObjectResult("参数错误");         }         else         {             context.Result = new StatusCodeResult(500);         }          context.ExceptionHandled = true; // 标记异常已被处理     } }

需要在

Startup.cs

中注册该Filter:

public void ConfigureServices(IServiceCollection services) {     services.AddControllers(options =>     {         options.Filters.Add(typeof(GlobalExceptionFilter));     }); }

全局异常处理的最佳实践是什么?

  • 记录详细的错误信息: 包括异常类型、消息、跟踪、发生时间等,以便于调试和排查问题。
  • 避免在全局异常处理程序中抛出异常: 这可能会导致无限循环或程序崩溃。
  • 不要吞噬异常: 如果无法处理异常,应该将其重新抛出,或者至少记录下来。
  • 考虑用户体验: 向用户显示友好的错误信息,而不是直接显示技术细节。
  • 使用专业的日志库: 如NLog, Serilog等,可以提供更强大的日志记录功能。
  • 区分不同类型的异常: 可以根据异常类型采取不同的处理方式,例如,对于已知类型的异常,可以进行特定的处理,对于未知类型的异常,可以进行通用的处理。
  • 在开发和测试环境中启用详细的错误报告: 这可以帮助你更快地发现和修复问题。
  • 在生产环境中禁用详细的错误报告: 避免向用户暴露敏感信息。
  • 定期审查日志文件: 分析错误趋势,找出潜在的问题。

全局异常处理并非万能的。 理想情况下,应该尽可能地在代码中处理异常,只有在无法预料的情况下才依赖全局异常处理。



评论(已关闭)

评论已关闭