Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 502|回复: 0

【第一篇笔记】C# 全局容错,全局异常

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-9-6 10:37:25 | 显示全部楼层 |阅读模式

    网上找到两个方式,一个简单的只是做个记录,另一个能像QQ一样提交到后台。

    方法一:

    static class Program
        {
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main()
            {
                try
                {
                    //设置应用程序处理异常方式:ThreadException处理
                    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                    //处理UI线程异常
                    Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                    //处理非UI线程异常
                    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    
                    #region 应用程序的主入口点
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                    #endregion
                }
                catch (Exception ex)
                {
                    string str = GetExceptionMsg(ex,string.Empty);
                    MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
    
    
            static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                string str = GetExceptionMsg(e.Exception, e.ToString());
                MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                //LogManager.WriteLog(str);
            }
    
            static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                string str = GetExceptionMsg(e.ExceptionObject as Exception, e.ToString());
                MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                //LogManager.WriteLog(str);
            }
    
            /// <summary>
            /// 生成自定义异常消息
            /// </summary>
            /// <param name="ex">异常对象</param>
            /// <param name="backStr">备用异常消息:当ex为null时有效</param>
            /// <returns>异常字符串文本</returns>
            static string GetExceptionMsg(Exception ex,string backStr)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("****************************异常文本****************************");
                sb.AppendLine("【出现时间】:" + DateTime.Now.ToString());
                if (ex != null)
                {                
                    sb.AppendLine("【异常类型】:" + ex.GetType().Name);
                    sb.AppendLine("【异常信息】:" + ex.Message);
                    sb.AppendLine("【堆栈调用】:" + ex.StackTrace);
                }
                else
                {
                    sb.AppendLine("【未处理异常】:" + backStr);
                }
                sb.AppendLine("***************************************************************");
                return sb.ToString();
            }
        }
    View Code

     

    方法二:

    转载于:王旭博客 » C# 全局异常处理。

    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报送的处理,对客户的错误解释界面,你可以根据自己的业务需求进行更改,总而言之把错误完整的保存下来即可。

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

    窗口的代码如下:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
     
    namespace WinformException
    {
        public partial class FrmBugReport : Form
        {
            #region 全局变量
            Exception _bugInfo;
            #endregion
     
            #region 构造函数
            /// <summary>
            /// Bug发送窗口
            /// </summary>
            /// <param name="bugInfo">Bug信息</param>
            public FrmBugReport(Exception bugInfo)
            {
                InitializeComponent();
                _bugInfo = bugInfo;
                this.txtBugInfo.Text = bugInfo.Message;
                lblErrorCode.Text = Guid.NewGuid().ToString();
            }
     
            /// <summary>
            /// Bug发送窗口
            /// </summary>
            /// <param name="bugInfo">Bug信息</param>
            /// <param name="errorCode">错误号</param>
            public FrmBugReport(Exception bugInfo, string errorCode)
            {
                InitializeComponent();
                _bugInfo = bugInfo;
                this.txtBugInfo.Text = bugInfo.Message;
                lblErrorCode.Text = errorCode;
            }
            #endregion
     
            #region 公开静态方法
            /// <summary>
            /// 提示Bug
            /// </summary>
            /// <param name="bugInfo">Bug信息</param>
            /// <param name="errorCode">错误号</param>
            public static void ShowBug(Exception bugInfo, string errorCode)
            {
                new FrmBugReport(bugInfo, errorCode).ShowDialog();
            }
     
            /// <summary>
            /// 提示Bug
            /// </summary>
            /// <param name="bugInfo">Bug信息</param>
            public static void ShowBug(Exception bugInfo)
            {
                ShowBug(bugInfo, Guid.NewGuid().ToString());
            }
            #endregion
     
            private void btnDetailsInfo_Click(object sender, EventArgs e)
            {
                MessageBox.Show("异常详细信息:" + _bugInfo.Message + "\r\n跟踪:" + _bugInfo.StackTrace);
            }
     
        }
    }
    View Code

     

    这个项目就完成了。

     

    3.2 构建异常测试程序

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

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

    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
     
    namespace WinformTest
    {
        static class Program
        {
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main()
            {
                //全局异常捕捉
                Application.ThreadException += Application_ThreadException; //UI线程异常
                AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; //多线程异常
     
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new FrmMain());
            }
     
            //UI线程异常
            static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                WinformException.FrmBugReport.ShowBug(e.Exception);
            }
     
            //多线程异常
            static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                WinformException.FrmBugReport.ShowBug((Exception)e.ExceptionObject);
            }
        }
    }

     

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

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

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

     

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

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

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

     

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

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
     
    namespace WinformTest
    {
        public partial class FrmMain : Form
        {
            public FrmMain()
            {
                InitializeComponent();
            }
     
            //普通异常测试
            private void btnTest1_Click(object sender, EventArgs e)
            {
                throw new Exception("啊..我这行代码异常了...");
            }
     
            //多线程异常测试
            private void btnTest2_Click(object sender, EventArgs e)
            {
                Thread th = new Thread(() => { throw new Exception("啊哦,异常错误。"); });
                th.IsBackground = true;
                th.Start();
            }
        }
    }

     

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

    exception4

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

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

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

     

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

     Thread t = new Thread((ThreadStart)delegate
    {
    try
    {
    throw new Exception("多线程异常");
    }
    catch (Exception error)
    {
    MessageBox.Show("线程异常:" + error.Message + Environment.NewLine + error.StackTrace);
    }
    });
    t.Start();
    View Code

     

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

     Thread t = new Thread((ThreadStart)delegate
    {
    try
    {
    throw new Exception("非窗体线程异常");
    }
    catch (Exception ex)
    {
    this.BeginInvoke((Action)delegate
    {
    throw ex;
    });
    }
    });
    t.Start();
     
    View Code

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-30 18:14 , Processed in 0.073518 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表