C# 异常处理总结
一 技术目标
程序构造的过程中,要有程序最终的标准: 可靠性、可用性是我比较关注的两个方面。其中可靠性又分为异常处理和数据完整性两个方面。
异常处理,老生常谈,我认为它是一个开发人员整体逻辑思维,开发模式,个人性情的体现。程序是逻辑的集合,达到正常功能性的开发只能是初级的目标。完善的异常处理才是综合能力的体现。
综上,异常处理应该以做到清晰,简单,友好为目标。这里,我总结下自己对于异常处理的理解和自己经常使用的一些方式。
二 技术过程
在开发的过程中,我经历过以下几个阶段的异常处理方式:
- 全局异常捕捉 + 异常日志
- 异常分类 + 异常日志
- 异常日志格式统一 + 异常分类 + 消息通知
1. 全局异常捕捉 + 异常日志
考虑异常处理功能的时候,首先就想到了统一处理的方式,统一管理是人类社会中经常用到的事务处理模式,集中之后,可以充分发挥标准化,规模化的作用。
下面以winform客户端为例,统一捕捉异常方式如下,在program.cs中注册如下事件:
// 统一异常处理
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
在处理程序中进行异常统一处理,记录日志:
/// <summary>
/// UI线程系统异常处理
/// </summary>
private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
// 添加日志
LogManager.Instance.Error($"系统运行期间捕获异常信息,信息如下:{e.Exception.Message}");
}
/// <summary>
/// 应用程序域异常
/// </summary>
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
string exMessage = (e.ExceptionObject as Exception).Message;
// 添加日志
LogManager.Instance.Error($"系统运行期间捕获异常信息,信息如下:{exMessage}");
}
以上方式存在几个问题:
- 关键业务异常处理流程和非关键的混在一起,无法对一些关键异常进行强保证;
- 异常日志放到一个文件中,难以定位问题。
2. 异常分类 + 异常日志
通过阅读《Effective C#》(http://product.dangdang.com/25282722.html),结合实际开发经验,对异常进行分类势在必行。
异常可分为三类:普通异常,强数据保证异常(数据完整性考虑),无异常处理。
普通异常:程序运行过程中未被处理的异常或者是影响较小的异常,只需要记录异常日志即可。
强数据保证异常:对业务来说的关键数据,处理失败后必须保证原始数据不被破坏,这类异常必须自己处理,不能抛出到全局中,开发中采用数据副本进行业务逻辑执行,保留原始数据,发生异常后,对原始数据进行恢复,达到数据回滚的目的。
无异常处理:这类异常在书中定义为不能发生异常的业务,要通过程序设计,管理规范等手段结合实现,但是实际过程中我并没有用过这类型异常,仅供参考。
3. 异常日志格式统一 + 异常分类 + 消息通知
第2点中,异常处理后的日志仍然被放到一起,不同的开发有不同的日志风格,一个日志拿出来看,凌乱、定位速度慢。所以有必要对异常进行日志格式统一,这里应用到了异常筛选器,统一日志目前定义格式如下:
异常等级为:【{type.ToString()}】,异常类:【{className}】,异常方法【{methodName}】,异常行数:【{lineNumber.ToString()}】,异常原因:【{e.Message}】,业务原因为:【{info}】
通过对Exception进行拓展,实现日志的记录,详细代码如下:
public static class ExceptionExtension
{
// 记录日志
public static bool Log(this Exception e, string info = "", ExceptionType type = ExceptionType.Normal)
{
#region 记录日志
StackTrace trace = new StackTrace(e, true);
var className = trace.GetFrame(0).GetMethod().ReflectedType.FullName; // 类名称
var methodName = e.TargetSite.Name; // 方法名称
var lineNumber = trace.GetFrame(0).GetFileLineNumber(); // 行号
LogManager.Instance.Error($"系统运行产生异常,异常等级为:【{type.ToString()}】,异常类:【{className}】,异常方法【{methodName}】,异常行数:【{lineNumber.ToString()}】,异常原因:【{e.Message}】,业务原因为:【{info}】");
#endregion 记录日志
return false;
}
}
使用如下:
这时候我们谈论的都是开发、调试、维护所应用的异常处理模式,还有一个很重要的是对客户友好型的提示,可以进行弹窗,短信等方式,分类呈现给客户。
这一块内容就需要根据业务进行分析,需要进行不同的处理。
三 技术模式
目前,程序开发中,我使用的便是2.3中的异常处理思维和模式,但是学无止境,事无常理,异常处理的方方面面仍然要继续积累。
四 存在问题
五 总结
开发的心态,谦逊的态度,不断的汲取知识,结合实际,不断前行。

浙公网安备 33010602011771号