咳,今天给大家带来一个关于C#中的异常处理,很多朋友在C#中的异常处理非常糟糕的,一个优秀的程序应该具备友好性,容错性,以及准确的异常信息收集的能力。很多Coder也想达到这样的指标呢?跟着我来,稳固你的程序吧!
1.本文目标
我们准备做一个程序,具备全局的异常捕获及处理能力,类似大多数知名程序那样弹个窗口,发送错误报告,友好的提示。类似腾讯QQ异常,Firefox异常等异常窗口来进行错误报送,如下图所示:
2.C#异常处理机制简介
C#也跟其他的OOP语言一样能够处理可预见的异常信息,如网络连接失败,文件读取失败,数组越界等异常。当你的程序遇到了异常的时候CLR会抛出一个异常给你,这样你就得到了一个处理异常的机会,这个异常会一层一层的返回给调用者,最后返回到Main方法的起始点中,但是如果你没有进行处理的话最终会被CLR处理,它将终止程序。
3. C#全局异常捕获处理
目前为止,很多的程序都是以感觉哪段代码可能异常就把它try起来然后弹个Message的方式进行提示,好一点处理的还会记录日志信息来解决。如果纯粹看简单的错误提示其实是很难找到错误的,尤其是程序越来越大的时候,甚至有时候你都不知道这个错误是哪个模块出现的,是怎么出现的,点击哪个按钮出现的!是不是得去问客户?在我看来极大多数情况是完全没有必要的,我们完全有能力捕获完整的异常。
好了,废话解释完毕,开始构建我们的具备异常处理捕获及处理能力的程序吧!这里以Winform举例,其他的都差不多,如WPF什么的都是可以捕获全局异常的。
3.1 构建Bug处理模块
首先我建了个Winform项目命名为 WinformException
用于处理Bug,为了利于以后项目复用 这个项目是单独用于处理Bug的,在该项目中构建了如下窗体。
这个用于对Bug报送的处理,对客户的错误解释界面,你可以根据自己的业务需求进行更改,总而言之把错误完整的保存下来即可。
出现错误不可怕,可怕的是出了错 你却不知道。
窗口的代码如下:
- usingSystem;
- usingSystem.Collections.Generic;
- usingSystem.ComponentModel;
- usingSystem.Data;
- usingSystem.Drawing;
- usingSystem.Text;
- usingSystem.Windows.Forms;
- namespaceWinformException
- {
- publicpartialclassFrmBugReport:Form
- {
- #region 全局变量
- Exception _bugInfo;
- #endregion
- #region 构造函数
- /// <summary>
- /// Bug发送窗口
- /// </summary>
- /// <param name="bugInfo">Bug信息</param>
- publicFrmBugReport(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>
- publicFrmBugReport(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>
- publicstaticvoidShowBug(Exception bugInfo,string errorCode)
- {
- newFrmBugReport(bugInfo, errorCode).ShowDialog();
- }
- /// <summary>
- /// 提示Bug
- /// </summary>
- /// <param name="bugInfo">Bug信息</param>
- publicstaticvoidShowBug(Exception bugInfo)
- {
- ShowBug(bugInfo,Guid.NewGuid().ToString());
- }
- #endregion
- privatevoid btnDetailsInfo_Click(object sender,EventArgs e)
- {
- MessageBox.Show("异常详细信息:"+ _bugInfo.Message+"\r\n跟踪:"+ _bugInfo.StackTrace);
- }
- }
- }
这个项目就完成了。
3.2 构建异常测试程序
接下来构建我们的测试程序,以及如何捕捉代码。我在解决方案中再建了一个Winform项目命名为WinformTest
做测试,如下图所示:
先来看看我们在 Program.cs
中做了什么手脚吧,这个就是全局捕捉异常的核心代码,Program.cs
代码如下:
- usingSystem;
- usingSystem.Collections.Generic;
- usingSystem.Windows.Forms;
- namespaceWinformTest
- {
- staticclassProgram
- {
- /// <summary>
- /// 应用程序的主入口点。
- /// </summary>
- [STAThread]
- staticvoidMain()
- {
- //全局异常捕捉
- Application.ThreadException+=Application_ThreadException;//UI线程异常
- AppDomain.CurrentDomain.UnhandledException+=CurrentDomain_UnhandledException;//多线程异常
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(newFrmMain());
- }
- //UI线程异常
- staticvoidApplication_ThreadException(object sender,System.Threading.ThreadExceptionEventArgs e)
- {
- WinformException.FrmBugReport.ShowBug(e.Exception);
- }
- //多线程异常
- staticvoidCurrentDomain_UnhandledException(object sender,UnhandledExceptionEventArgs e)
- {
- WinformException.FrmBugReport.ShowBug((Exception)e.ExceptionObject);
- }
- }
- }
第一行我注册了UI线程异常处理事件
- Application.ThreadException+=Application_ThreadException;//UI线程异常
这个用于捕获主线程的错误,也就是UI,大多数异常都会聚集在此,我们在该事件中处理了异常,程序则不会强制退出。
然后第二行注册了其他多线程异常处理事件(除UI之外的线程)
- AppDomain.CurrentDomain.UnhandledException+=CurrentDomain_UnhandledException;//多线程异常
这个用于捕获主线程之外的所有线程的异常,但是无法让程序不被强制退出,当在这里面的代码执行完毕后程序依然会退出!不过幸运的是我们有其他的办法来解决。
然后看看测试窗体 FrmMain.cs
的代码如下:
- usingSystem;
- usingSystem.Collections.Generic;
- usingSystem.ComponentModel;
- usingSystem.Data;
- usingSystem.Drawing;
- usingSystem.Text;
- usingSystem.Threading;
- usingSystem.Windows.Forms;
- namespaceWinformTest
- {
- publicpartialclassFrmMain:Form
- {
- publicFrmMain()
- {
- InitializeComponent();
- }
- //普通异常测试
- privatevoid btnTest1_Click(object sender,EventArgs e)
- {
- thrownewException("啊..我这行代码异常了...");
- }
- //多线程异常测试
- privatevoid btnTest2_Click(object sender,EventArgs e)
- {
- Thread th =newThread(()=>{thrownewException("啊哦,异常错误。");});
- th.IsBackground=true;
- th.Start();
- }
- }
- }
其实就是两个简单的测试而已,点击按钮会弹出如下界面。
我们可以在确定按钮中编写发送到数据库,或者是把bug详细信息存放到txt中。拿到了Exception
,由你任意处置吧,我这里把Exception
的StackTrace
属性展示到了错误详细信息按钮上,不会看StackTrace
的,该反省下了。耐心看下就明白了,是很简单的,它对Bug是如何出现的步骤表示的非常清楚。
好了到此为止,Bug处理也就OK了,还算非常简单的,只是可能我长篇大论了。哈..下次尽量简短..现在应该掌握了对异常的合理处理了吧。
该解决方案的源码下载:WinformException
小知识:如何处理多线程中的异常,让程序不会强制退出。
你可以这样,把多线程中的任务全部try起来。
- Thread t =newThread((ThreadStart)delegate
- {
- try
- {
- thrownewException("多线程异常");
- }
- catch(Exception error)
- {
- MessageBox.Show("线程异常:"+ error.Message+Environment.NewLine+ error.StackTrace);
- }
- });
- t.Start();
你还可以这样,把异常抛回主线程,这个比较推荐。
- Thread t =newThread((ThreadStart)delegate
- {
- try
- {
- thrownewException("非窗体线程异常");
- }
- catch(Exception ex)
- {
- this.BeginInvoke((Action)delegate
- {
- throw ex;
- });
- }
- });
- t.Start();
至此,还有什么疑问或者更好的建议欢迎在此评论补充或进行讨论。
感谢。
相关推荐
这里建立了一个有关异常处理的对话框类,来实现异常的捕捉。通过使用ThreadException, App.CurrentDomain.UnhandledException捕捉程序里不可预知的异常,可以帮助开发者方便的找到发生异常的位置。
本教程将深入探讨如何在C#中实现全局异常处理,以及它对代码健壮性的重要性。 首先,让我们理解C#中的异常处理基础。在C#中,我们使用`try-catch`语句块来捕获和处理可能抛出的异常。当`try`块中的代码发生异常时,...
4. **绑定上下文**:为了在异常处理逻辑中获取到更多的上下文信息(如用户信息、请求信息等),可以使用依赖注入来传递这些信息,或者使用静态类、ThreadLocal等存储全局状态。 5. **反射技术**:在某些情况下,...
全局异常处理是软件开发中的一个重要概念,特别是在大型项目或复杂系统中,确保程序在遇到错误时能够优雅地处理并提供反馈至关重要。这篇文章将深入探讨全局异常处理的实现,包括其重要性、常见方法以及如何在不同...
全局异常处理是软件开发中的一个重要概念,特别是在Java、Python、C#等面向对象的语言中,它为程序提供了统一的错误捕获和处理机制。全局异常处理可以确保在程序的任何地方发生异常时,都能得到适当的处理,避免程序...
"winform捕捉全局异常"这个主题就是关于如何在WinForm应用程序中设置一个全局异常处理机制,以便在程序运行过程中捕获和处理未预期的错误,避免程序突然崩溃。下面将详细介绍这个知识点。 1. **异常处理基础**: ...
在C# WinForm应用开发中,全局错误处理是至关重要的,因为它可以帮助我们捕获和管理程序运行时可能遇到的各种异常,确保程序的稳定性和用户体验。本文将深入探讨如何实现C# WinForm的全局错误捕捉,并解释如何在发生...
本篇文章详细介绍了如何使用C#实现全局键盘钩子的功能,包括定义委托、安装与卸载钩子、处理按键事件等关键步骤。通过以上介绍,读者可以更好地理解全局钩子的工作原理,并能够实际应用到自己的项目中。需要注意的是...
8. **异常处理**:良好的错误处理和异常处理机制是确保程序稳定运行的关键,尤其是在涉及到系统级操作时。 9. **程序打包与部署**:最后,了解如何将这个程序打包成安装包或单文件执行程序,以便用户可以方便地安装...
关于异常处理,作为程序员的我们肯定不陌生,记得在介绍 AOP的时候,我们讲过通过AOP可以统一截获异常。那么在我们的WebApi里面一般是怎么处理异常的呢,今天这一篇,博主带着大家一起来实践下WebApi的异常处理。 为...
C#全局钩子的实现通常涉及到使用C++编写一个动态链接库(DLL),因为Windows API的钩子函数通常是C语言风格的,然后在C#应用程序中调用这个DLL来设置和处理钩子。本文将深入探讨C#全局钩子的实现原理、步骤以及如何...
本文将介绍一种由SamWang提出的解决方案,用于在C# WinForm应用中实现全局异常捕获。 首先,我们需要在`Program.cs`文件中的`Main`方法中进行设置。这里的关键在于注册事件处理器,以处理两种类型的异常:UI线程...
4. 为了保持代码的可读性,工具可能还会提供自定义配置,允许开发者指定只对特定类别的方法添加异常处理,或者设置全局处理策略。 5. 最后,工具会更新解决方案(sln)文件和用户选项(suo)文件,以反映代码变动。 ...
在.NET开发中,创建一个全局快捷键系统...在实际开发中,还需要考虑多线程、异常处理、权限控制等复杂因素。通过深入理解和运用上述知识点,你可以创建一个强大且灵活的全局快捷键管理系统,提升你的应用程序用户体验。
在WinForm应用中,异常处理不仅仅是简单的try-catch-finally结构,还可以利用Application.ThreadException事件全局处理线程级异常。这个事件允许你在应用程序级别捕获和处理任何未处理的UI线程异常,避免程序意外...
2. **GlobalExceptionHandler**: 一个全局异常处理器,用于捕获未被捕获的异常并打印堆栈信息。 3. **LoggingModule**: 负责记录和输出日志,包括控制台输出和文件记录。 4. **UtilityFunctions**: 提供一些辅助函数...
C# WinForm全局异常捕获方法 在主程序入口设置应用程序处理异常方式:ThreadException处理 处理UI线程异常和非UI线程异常 生成自定义异常消息,显示异常对象 备用异常消息:当ex为null时有效和异常字符串文本
在实际开发中,你可能还需要添加更多的功能,如日志记录、错误处理和定时任务等。此外,还可以使用控制台应用程序作为调试入口,在服务未安装之前测试其功能。 总的来说,创建一个基于C#的Windows Service服务并不...
在编程世界中,异常处理是一项至关重要的技能,无论是Java、C语言、C++还是C#,甚至是用于服务器端脚本的jsp(JavaServer Pages),都包含有异常处理机制。异常处理是程序在运行过程中遇到错误时的一种恢复策略,它...