C# 全局异常处理

来源:互联网 发布:用mac整理iphone照片 编辑:程序博客网 时间:2024/04/30 03:09


咳,今天给大家带来一个关于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. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Text;
  7. using System.Windows.Forms;
  8.  
  9. namespace WinformException
  10. {
  11.     public partial class FrmBugReport : 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.         public FrmBugReport(Exception bugInfo)
  23.         {
  24.             InitializeComponent();
  25.             _bugInfo = bugInfo;
  26.             this.txtBugInfo.Text = bugInfo.Message;
  27.             lblErrorCode.Text = Guid.NewGuid().ToString();
  28.         }
  29.  
  30.         /// <summary
    </pre><br />></li><li class="L0"><span class="pln">        </span><span class="com">/// Bug发送窗口</span></li><li class="L1"><span class="pln">        </span><span class="com">/// </summary></span></li><li class="L2"><span class="pln">        </span><span class="com">/// <param name="bugInfo">Bug信息</param></span></li><li class="L3"><span class="pln">        </span><span class="com">/// <param name="errorCode">错误号</param></span></li><li class="L4"><span class="pln">        </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">FrmBugReport</span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> bugInfo</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> errorCode</span><span class="pun">)</span></li><li class="L5"><span class="pln">        </span><span class="pun">{</span></li><li class="L6"><span class="pln">            </span><span class="typ">InitializeComponent</span><span class="pun">();</span></li><li class="L7"><span class="pln">            _bugInfo </span><span class="pun">=</span><span class="pln"> bugInfo</span><span class="pun">;</span></li><li class="L8"><span class="pln">            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">txtBugInfo</span><span class="pun">.</span><span class="typ">Text</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> bugInfo</span><span class="pun">.</span><span class="typ">Message</span><span class="pun">;</span></li><li class="L9"><span class="pln">            lblErrorCode</span><span class="pun">.</span><span class="typ">Text</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> errorCode</span><span class="pun">;</span></li><li class="L0"><span class="pln">        </span><span class="pun">}</span></li><li class="L1"><span class="pln">        </span><span class="com">#endregion</span></li><li class="L2"><span class="pln"> </span></li><li class="L3"><span class="pln">        </span><span class="com">#region 公开静态方法</span></li><li class="L4"><span class="pln">        </span><span class="com">/// <summary></span></li><li class="L5"><span class="pln">        </span><span class="com">/// 提示Bug</span></li><li class="L6"><span class="pln">        </span><span class="com">/// </summary></span></li><li class="L7"><span class="pln">        </span><span class="com">/// <param name="bugInfo">Bug信息</param></span></li><li class="L8"><span class="pln">        </span><span class="com">/// <param name="errorCode">错误号</param></span></li><li class="L9"><span class="pln">        </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">ShowBug</span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> bugInfo</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> errorCode</span><span class="pun">)</span></li><li class="L0"><span class="pln">        </span><span class="pun">{</span></li><li class="L1"><span class="pln">            </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FrmBugReport</span><span class="pun">(</span><span class="pln">bugInfo</span><span class="pun">,</span><span class="pln"> errorCode</span><span class="pun">).</span><span class="typ">ShowDialog</span><span class="pun">();</span></li><li class="L2"><span class="pln">        </span><span class="pun">}</span></li><li class="L3"><span class="pln"> </span></li><li class="L4"><span class="pln">        </span><span class="com">/// <summary></span></li><li class="L5"><span class="pln">        </span><span class="com">/// 提示Bug</span></li><li class="L6"><span class="pln">        </span><span class="com">/// </summary></span></li><li class="L7"><span class="pln">        </span><span class="com">/// <param name="bugInfo">Bug信息</param></span></li><li class="L8"><span class="pln">        </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">ShowBug</span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> bugInfo</span><span class="pun">)</span></li><li class="L9"><span class="pln">        </span><span class="pun">{</span></li><li class="L0"><span class="pln">            </span><span class="typ">ShowBug</span><span class="pun">(</span><span class="pln">bugInfo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Guid</span><span class="pun">.</span><span class="typ">NewGuid</span><span class="pun">().</span><span class="typ">ToString</span><span class="pun">());</span></li><li class="L1"><span class="pln">        </span><span class="pun">}</span></li><li class="L2"><span class="pln">        </span><span class="com">#endregion</span></li><li class="L3"><span class="pln"> </span></li><li class="L4"><span class="pln">        </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> btnDetailsInfo_Click</span><span class="pun">(</span><span class="kwd">object</span><span class="pln"> sender</span><span class="pun">,</span><span class="pln"> </span><span class="typ">EventArgs</span><span class="pln"> e</span><span class="pun">)</span></li><li class="L5"><span class="pln">        </span><span class="pun">{</span></li><li class="L6"><span class="pln">            </span><span class="typ">MessageBox</span><span class="pun">.</span><span class="typ">Show</span><span class="pun">(</span><span class="str">"异常详细信息:"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> _bugInfo</span><span class="pun">.</span><span class="typ">Message</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"\r\n跟踪:"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> _bugInfo</span><span class="pun">.</span><span class="typ">StackTrace</span><span class="pun">);</span></li><li class="L7"><span class="pln">        </span><span class="pun">}</span></li><li class="L8"><span class="pln"> </span></li><li class="L9"><span class="pln">    </span><span class="pun">}</span></li><li class="L0"><span class="pun">}</span></li></ol>

    这个项目就完成了。

     

    3.2 构建异常测试程序

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

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

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Windows.Forms;
    4.  
    5. namespace WinformTest
    6. {
    7.     static class Program
    8.     {
    9.         /// <summary>
    10.         /// 应用程序的主入口点。
    11.         /// </summary>
    12.         [STAThread]
    13.         static void Main()
    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(new FrmMain());
    22.         }
    23.  
    24.         //UI线程异常
    25.         static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    26.         {
    27.             WinformException.FrmBugReport.ShowBug(e.Exception);
    28.         }
    29.  
    30.         //多线程异常
    31.         static void CurrentDomain_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. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Text;
    7. using System.Threading;
    8. using System.Windows.Forms;
    9.  
    10. namespace WinformTest
    11. {
    12.     public partial class FrmMain : Form
    13.     {
    14.         public FrmMain()
    15.         {
    16.             InitializeComponent();
    17.         }
    18.  
    19.         //普通异常测试
    20.         private void btnTest1_Click(object sender, EventArgs e)
    21.         {
    22.             throw new Exception("啊..我这行代码异常了...");
    23.         }
    24.  
    25.         //多线程异常测试
    26.         private void btnTest2_Click(object sender, EventArgs e)
    27.         {
    28.             Thread th = new Thread(() => { throw new Exception("啊哦,异常错误。"); });
    29.             th.IsBackground = true;
    30.             th.Start();
    31.         }
    32.     }
    33. }

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

    exception4

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

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

    该解决方案的源码下载:WinformException

     

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

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

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

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

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

    感谢。




    本文转载至http://www.wxzzz.com/1173.html ,转载下来方便自己以后查阅。

0 0
原创粉丝点击