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}");

        }

以上方式存在几个问题:

  1. 关键业务异常处理流程和非关键的混在一起,无法对一些关键异常进行强保证;
  2. 异常日志放到一个文件中,难以定位问题。

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中的异常处理思维和模式,但是学无止境,事无常理,异常处理的方方面面仍然要继续积累。

存在问题

总结

开发的心态,谦逊的态度,不断的汲取知识,结合实际,不断前行。

 

posted @ 2021-02-23 13:04  慢慢zero  阅读(389)  评论(0)    收藏  举报