`

C# 全局异常处理

    博客分类:
  • C#
 
阅读更多

咳,今天给大家带来一个关于C#中的异常处理,很多朋友在C#中的异常处理非常糟糕的,一个优秀的程序应该具备友好性,容错性,以及准确的异常信息收集的能力。很多Coder也想达到这样的指标呢?跟着我来,稳固你的程序吧!

 

1.本文目标

我们准备做一个程序,具备全局的异常捕获及处理能力,类似大多数知名程序那样弹个窗口,发送错误报告,友好的提示。类似腾讯QQ异常,Firefox异常异常窗口来进行错误报送,如下图所示:

exception1

2.C#异常处理机制简介

C#也跟其他的OOP语言一样能够处理可预见的异常信息,如网络连接失败,文件读取失败,数组越界等异常。当你的程序遇到了异常的时候CLR会抛出一个异常给你,这样你就得到了一个处理异常的机会,这个异常会一层一层的返回给调用者,最后返回到Main方法的起始点中,但是如果你没有进行处理的话最终会被CLR处理,它将终止程序。

 

3. C#全局异常捕获处理

目前为止,很多的程序都是以感觉哪段代码可能异常就把它try起来然后弹个Message的方式进行提示,好一点处理的还会记录日志信息来解决。如果纯粹看简单的错误提示其实是很难找到错误的,尤其是程序越来越大的时候,甚至有时候你都不知道这个错误是哪个模块出现的,是怎么出现的,点击哪个按钮出现的!是不是得去问客户?在我看来极大多数情况是完全没有必要的,我们完全有能力捕获完整的异常
好了,废话解释完毕,开始构建我们的具备异常处理捕获及处理能力的程序吧!这里以Winform举例,其他的都差不多,如WPF什么的都是可以捕获全局异常

3.1 构建Bug处理模块

首先我建了个Winform项目命名为 WinformException 用于处理Bug,为了利于以后项目复用 这个项目是单独用于处理Bug的,在该项目中构建了如下窗体。

exception2

这个用于对Bug报送的处理,对客户的错误解释界面,你可以根据自己的业务需求进行更改,总而言之把错误完整的保存下来即可。

出现错误不可怕,可怕的是出了错 你却不知道。

窗口的代码如下:

  1. usingSystem;
  2. usingSystem.Collections.Generic;
  3. usingSystem.ComponentModel;
  4. usingSystem.Data;
  5. usingSystem.Drawing;
  6. usingSystem.Text;
  7. usingSystem.Windows.Forms;
  8.  
  9. namespaceWinformException
  10. {
  11.     publicpartialclassFrmBugReport:Form
  12.     {
  13.         #region 全局变量
  14.         Exception _bugInfo;
  15.         #endregion
  16.  
  17.         #region 构造函数
  18.         /// <summary>
  19.         /// Bug发送窗口
  20.         /// </summary>
  21.         /// <param name="bugInfo">Bug信息</param>
  22.         publicFrmBugReport(Exception bugInfo)
  23.         {
  24.             InitializeComponent();
  25.             _bugInfo = bugInfo;
  26.             this.txtBugInfo.Text= bugInfo.Message;
  27.             lblErrorCode.Text=Guid.NewGuid().ToString();
  28.         }
  29.  
  30.         /// <summary>
  31.         /// Bug发送窗口
  32.         /// </summary>
  33.         /// <param name="bugInfo">Bug信息</param>
  34.         /// <param name="errorCode">错误号</param>
  35.         publicFrmBugReport(Exception bugInfo,string errorCode)
  36.         {
  37.             InitializeComponent();
  38.             _bugInfo = bugInfo;
  39.             this.txtBugInfo.Text= bugInfo.Message;
  40.             lblErrorCode.Text= errorCode;
  41.         }
  42.         #endregion
  43.  
  44.         #region 公开静态方法
  45.         /// <summary>
  46.         /// 提示Bug
  47.         /// </summary>
  48.         /// <param name="bugInfo">Bug信息</param>
  49.         /// <param name="errorCode">错误号</param>
  50.         publicstaticvoidShowBug(Exception bugInfo,string errorCode)
  51.         {
  52.             newFrmBugReport(bugInfo, errorCode).ShowDialog();
  53.         }
  54.  
  55.         /// <summary>
  56.         /// 提示Bug
  57.         /// </summary>
  58.         /// <param name="bugInfo">Bug信息</param>
  59.         publicstaticvoidShowBug(Exception bugInfo)
  60.         {
  61.             ShowBug(bugInfo,Guid.NewGuid().ToString());
  62.         }
  63.         #endregion
  64.  
  65.         privatevoid btnDetailsInfo_Click(object sender,EventArgs e)
  66.         {
  67.             MessageBox.Show("异常详细信息:"+ _bugInfo.Message+"\r\n跟踪:"+ _bugInfo.StackTrace);
  68.         }
  69.  
  70.     }
  71. }

这个项目就完成了。

 

3.2 构建异常测试程序

接下来构建我们的测试程序,以及如何捕捉代码。我在解决方案中再建了一个Winform项目命名为WinformTest做测试,如下图所示:

exception3 先来看看我们在 Program.cs 中做了什么手脚吧,这个就是全局捕捉异常的核心代码,Program.cs 代码如下:

  1. usingSystem;
  2. usingSystem.Collections.Generic;
  3. usingSystem.Windows.Forms;
  4.  
  5. namespaceWinformTest
  6. {
  7.     staticclassProgram
  8.     {
  9.         /// <summary>
  10.         /// 应用程序的主入口点。
  11.         /// </summary>
  12.         [STAThread]
  13.         staticvoidMain()
  14.         {
  15.             //全局异常捕捉
  16.             Application.ThreadException+=Application_ThreadException;//UI线程异常
  17.             AppDomain.CurrentDomain.UnhandledException+=CurrentDomain_UnhandledException;//多线程异常
  18.  
  19.             Application.EnableVisualStyles();
  20.             Application.SetCompatibleTextRenderingDefault(false);
  21.             Application.Run(newFrmMain());
  22.         }
  23.  
  24.         //UI线程异常
  25.         staticvoidApplication_ThreadException(object sender,System.Threading.ThreadExceptionEventArgs e)
  26.         {
  27.             WinformException.FrmBugReport.ShowBug(e.Exception);
  28.         }
  29.  
  30.         //多线程异常
  31.         staticvoidCurrentDomain_UnhandledException(object sender,UnhandledExceptionEventArgs e)
  32.         {
  33.             WinformException.FrmBugReport.ShowBug((Exception)e.ExceptionObject);
  34.         }
  35.     }
  36. }

第一行我注册了UI线程异常处理事件

  1.  Application.ThreadException+=Application_ThreadException;//UI线程异常

这个用于捕获主线程的错误,也就是UI,大多数异常都会聚集在此,我们在该事件中处理了异常,程序则不会强制退出。

 

然后第二行注册了其他多线程异常处理事件(除UI之外的线程)

  1.  AppDomain.CurrentDomain.UnhandledException+=CurrentDomain_UnhandledException;//多线程异常

这个用于捕获主线程之外的所有线程的异常但是无法让程序不被强制退出,当在这里面的代码执行完毕后程序依然会退出!不过幸运的是我们有其他的办法来解决

 

然后看看测试窗体 FrmMain.cs 的代码如下:

  1. usingSystem;
  2. usingSystem.Collections.Generic;
  3. usingSystem.ComponentModel;
  4. usingSystem.Data;
  5. usingSystem.Drawing;
  6. usingSystem.Text;
  7. usingSystem.Threading;
  8. usingSystem.Windows.Forms;
  9.  
  10. namespaceWinformTest
  11. {
  12.     publicpartialclassFrmMain:Form
  13.     {
  14.         publicFrmMain()
  15.         {
  16.             InitializeComponent();
  17.         }
  18.  
  19.         //普通异常测试
  20.         privatevoid btnTest1_Click(object sender,EventArgs e)
  21.         {
  22.             thrownewException("啊..我这行代码异常了...");
  23.         }
  24.  
  25.         //多线程异常测试
  26.         privatevoid btnTest2_Click(object sender,EventArgs e)
  27.         {
  28.             Thread th =newThread(()=>{thrownewException("啊哦,异常错误。");});
  29.             th.IsBackground=true;
  30.             th.Start();
  31.         }
  32.     }
  33. }

其实就是两个简单的测试而已,点击按钮会弹出如下界面。

exception4

我们可以在确定按钮中编写发送到数据库,或者是把bug详细信息存放到txt中。拿到了Exception,由你任意处置吧,我这里把ExceptionStackTrace属性展示到了错误详细信息按钮上,不会看StackTrace的,该反省下了。耐心看下就明白了,是很简单的,它对Bug是如何出现的步骤表示的非常清楚。

好了到此为止,Bug处理也就OK了,还算非常简单的,只是可能我长篇大论了。哈..下次尽量简短..现在应该掌握了对异常的合理处理了吧。

该解决方案的源码下载WinformException

 

小知识:如何处理多线程中的异常,让程序不会强制退出
你可以这样,把多线程中的任务全部try起来。

  1.  Thread t =newThread((ThreadStart)delegate
  2. {
  3. try
  4. {
  5. thrownewException("多线程异常");
  6. }
  7. catch(Exception error)
  8. {
  9. MessageBox.Show("线程异常:"+ error.Message+Environment.NewLine+ error.StackTrace);
  10. }
  11. });
  12. t.Start();

你还可以这样,把异常抛回主线程,这个比较推荐。

  1.  Thread t =newThread((ThreadStart)delegate
  2. {
  3. try
  4. {
  5. thrownewException("非窗体线程异常");
  6. }
  7. catch(Exception ex)
  8. {
  9. this.BeginInvoke((Action)delegate
  10. {
  11. throw ex;
  12. });
  13. }
  14. });
  15. t.Start();

至此,还有什么疑问或者更好的建议欢迎在此评论补充或进行讨论。

感谢。

分享到:
评论

相关推荐

    全局异常捕捉 c#WinForm异常处理

    这里建立了一个有关异常处理的对话框类,来实现异常的捕捉。通过使用ThreadException, App.CurrentDomain.UnhandledException捕捉程序里不可预知的异常,可以帮助开发者方便的找到发生异常的位置。

    C# .net Aop 动态截获异常

    利用特性,绑定上下文,代理,反射等技术动态截获异常,实现切面编程

    C# WebApi 异常处理解决方案

    关于异常处理,作为程序员的我们肯定不陌生,记得在介绍 AOP的时候,我们讲过通过AOP可以统一截获异常。那么在我们的WebApi里面一般是怎么处理异常的呢,今天这一篇,博主带着大家一起来实践下WebApi的异常处理。 为...

    C# WinForm捕获全局变量异常 SamWang解决方法

    许多小公司的项目都缺少异常处理模块...以下是根据网上找的C#winform全局异常捕获做了点修改。(等项目异常处理全部完成后,将心得体会做个记录,此处暂对全局异常捕获做个记录) 代码如下: static class Program { ///

    AutoWrapper:一个简单但可自定义的全局异常处理程序和用于ASP.NET Core API的Http响应包装器

    AutoWrapper是一个简单但可自定义的全局HTTP异常处理程序和针对ASP.NET Core API的响应包装器。 它使用ASP.NET Core middleware来拦截传入的HTTP请求,并通过为成功和错误结果提供一致的响应格式来自动为您包装响应...

    C# 编程指南 C# 随身参考 Wego开发组专用

    异常和异常处理(C# 编程指南) 互操作性(C# 编程指南) 线程处理(C# 编程指南) 性能(C# 编程指南) 反射(C# 编程指南) C# DLL(C# 编程指南) 安全性(C# 编程指南) 请参见 其他资源 C# 参考 ...

    C# 编程指南 [微软官方 MSDN 节选]

    C# 编程指南 [微软官方 MSDN 节选] ...异常和异常处理(C# 编程指南) 互操作性(C# 编程指南) 线程处理(C# 编程指南) 性能(C# 编程指南) 反射(C# 编程指南) C# DLL(C# 编程指南) 安全性(C# 编程指南) ……

    轻松学C#(图解版)

    第三篇是应用技术篇,主要介绍的是异常处理、文件和流、委托、事件、Lambda表达式、命名空间、预处理器、程序集、运行时类型标识、反射、特性、泛型、LINQ和数据库开发等。 =======================================...

    C#GDI+图形程序设计源码

    c#图形书中最经典的一本书当中包括饼图,条形图,绘图板制作等 第1章 GDI+ ——下一代图形接口 1.1 理解GDI+ 1.2 探索GDI+ 的功能 1.3 从GDI的角度学习GDI+ 1.4 .NET中的GDI+ 名称空间和...附录A .NET中的异常处理

    C#微软培训资料

    8.4 异常处理语句 .95 8.5 小 结 .100 第三部分 面向对象的 C#.101 第九章 面向对象的程序设计 .101 9.1 面向对象的基本概念.101 9.2 对象的模型技术 .103 9.3 面向对象的分析 .105 9.4 面向对象的设计...

    在一小时内学会 C#(txt版本)

    异常处理 ? .NET 库 编程结构 和 C++ 一样,C# 是大小写敏感的。半角分号(;)是语句分隔符。和 C++ 有所区别的是,C# 中没有单独的声明(头)和实现(CPP)文件。所有代码(类声明和实现)都放在扩展名为 cs 的...

    CLR.via.C#.(中文第3版)(自制详细书签)

    · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、反射和C#的dynamic类型来构造具有动态扩展能力的应用程序 本书作者作者Jeffrey Richter,.NET和Windows编程领域当之无愧的大师和权威,...

    c#扫雷源代码

    1)ExceptionHandler负责统一处理系统中的异常。 2)PaneState是一个枚举,代表一个CrlPane的各种状态 3)Program是全局入口。 4)Resources目录下是所以程序所需的图片资源,这里的资源将作为内嵌资源,通过...

    GlobalExceptionHandling:全局处理所有未处理的异常

    GlobalExceptionHandling 全局处理所有未处理的异常。 目的:我们这里的目的是获取异常的堆栈跟踪数据,以帮助我们确定是在Release Mode还是在Debug Mode导致问题的确切原因。 我们将能够了解问题及其原因。 我们会...

    CLR.via.C#.(中文第3版)(自制详细书签)Part2

    · 借助于异常处理来进行状态管理 · 使用CLR寄宿、AppDomain、程序集加载、反射和C#的dynamic类型来构造具有动态扩展能力的应用程序 本书作者作者Jeffrey Richter,.NET和Windows编程领域当之无愧的大师和权威,以...

    C#XML入门经典 C#编程人员必备的XML技能.part2

    XML模式和.NET &lt;br&gt;11.1 在Visual Studio.NET中利用模式编辑器 11.1.1 从XML文档中生成模式 11.1.2 通过编程方式验证XML 11.1.3 处理异常和利用ValidationEventHandler 11.2 XSD和用xsd.exe进行串行...

Global site tag (gtag.js) - Google Analytics