业务应该这么写--异常处理
最近在帮同事调试代码,解决Bug的时候,搞了半天发现竟然是因为try{} catch{ return false} 而引起的。所以好好“教训”了这位同事一番。先大概总结:1、我觉得要写try catch的话呢,就必须认认真真的把try写好,还要把catch也写好(很多同事就是把try认认真真的写了,而catch呢就很随意)。2、我一般认为是异常信息要对解决这个异常有帮助,通过堆栈信息能够定位到具体的出错的地方。3、异常和日志一般是标配。欢迎大家留言讨论。
(一) 编码过程中,常见的案例
先看看下面几个常见的例子。
一般来说,我们都是这么写代码的,在数据库访问层,查数据出错了,我们都是做如下处理,请看下面代码。
public static UserEntity GetUserInfo(string userName){ UserEntity userEntity = null; try{ //数据库连接 //准备SQL, //返回数据 //这里报异常了 userEntity.Id.ToString(); } catch (Exception ex){
//在这里把异常抛出去
throw ex; } return userEntity; }
当我们调用上端这段代码的时候,从堆栈信息里面的行数是throw ex的行数,明明是userEntity.Id.ToString();报错了,堆栈信息却定位到了throw ex 这里,说明这里存在一个堆栈信息的覆盖问题,这样呢,会导致我们对错误的定位也不够明确了,还是要一行行调试才知道问题出在哪里,堆栈信息处于无用的状态。
(二) 异常处理的正确姿势
1、一般来说上端必须有,能保证程序不会因为异常死掉(那些全局钩子(MVC 里面ExceptionFilter,Winform的全局捕捉等等也要有)
2、不要到处写try catch。不过有些时候,也要写,比如按照事务进行更新,删除操作等等,有可能失败要进行回滚的话要有。
3、还有就是我们底层的框架,比如写日志等等,这里必须要把try-catch 给写上。因为写日志这些操作是不应该影响业务流程的。
4、如果因为知识水平的限制,而不断用try catch,那就应该去提升自己。
5、关于try catch损失性能问题,损失不了多少性能,首先要保证业务系统够稳才是硬道理。
(三)解决刚刚开始那个问题的做法
做法一:在调用层面写try catch.并且做好日志记录,(也就是刚刚说的,在上端写try catch);
做法二:定义一个通用的返回类型;
public class ServiceResult { /// <summary> /// 状态码(1,代表正常,0、代表出异常) /// </summary> public int StatusCode { get; set; } /// <summary> /// 异常信息 /// </summary> public string ErrorMsg { get; set; } } public class ServiceResult<T> : ServiceResult { public T Data { get; set; } }
(四)对于异常的一个总结
1、正常业务流程不应该用异常来处理,尽量使用Tester-Doer模式;
2、异常和日志是标配(你可以定义一些自己搞的异常,但是日志里面一定要记录;
3、尽量在上端记录异常(假如有一个BLL,既可能被winform调用,也可能被控制台调用)