一、异常的构成
new Exception() 创建异常对象
throw 抛出异常对象(主要性能损耗位置)
try{}catch{} 捕捉异常对象
C#里面异常对象分为两个子类ApplicationException、SystemException,前者主要是提供给应用程序自定义的异常类,后者是提供给系统定义的异常类
二、如何使用异常
异常的正常逻辑是:由底层抛出,由高层处理
1、底层方法或者提供给其他人使用方法内的一些参数过滤或其它异常应该向上抛出
如(借鉴现成代码懒得写了):
public void InsertUser(User user) { if(user==null) { throw new ArgumentNullException("参数user为null"); } //调用Orm }
2、上层应该加上try{}catch{}来捕捉异常并处理
如:
try { bll.InsertUser(null); } catch (ArgumentNullException e) { LogHelper.Write(e.Message); }
3、避免一些错误的异常处理方式
如(借鉴现成代码懒得写了):
/* 用异常验证用户输入 用户输入的合法性验证是属于业务逻辑的一部分,绝对不要用异常去处理,注意,是用户输入,所以这个经验仅限于表现层逻辑 */ //典型错误1 try { int i=int.Parse(textBox1.Text); } catch(Exception ex) { alert(“不要输入非数字”); } //典型错误2 void ValidateInput(int i) { if(i<0&&i>100) { throw new Exception("输入数据范围错误"); } } /* 将异常交由给底层处理 这个错误在于完全不验证用户输入而直接把数据的验证抛向数据库,等待数据库报错来判断用户输入的正确性,这个是非常致命的错误,很多注入漏洞都是由此产生的 */ //典型错误3 try { string name=Request.QueryString["xx"]; List<User> userls=User.QueryUserByName(name); } catch(SqlException ex) { } /* 完全不用异常机制 产生这个错误肯定是一个非常脑残的决定造成的。不过很多时候某些不了解异常机制的人,由于对异常的性能开销的恐惧感,经常会做出这么脑残的决定 性能倒是高了,但是系统异常怎么办呢?一旦数据库出错就只等着系统崩溃了。某些有经验的说我会把下面的try{}catch{}起来,不过那不是脱了裤子放屁么,异常都抛出来了,开销已经产生了,结果换来的是牺牲了异常对象的丰富信息而换来了畸形的系统逻辑。性能也没得到提高 */ //典型错误4 public bool InsertUser(User user,ref int errcode) { if(user==null) { errcode=110;//参数为空错误的代码 return false; } //调用Orm }
三、异常的性能测试
结论:
1、new Exception() 异常对象和创建普通对象的性能损耗没太大差别
2、throw 抛出异常时会造成系统性能损耗,主要在于“填充运行的堆栈信息”、“记录异常快照”等
3、try{}catch{}不会造成明显的系统开销,加不加性能区别不大
4、对外提供的方法尽可能抛出异常,避免程序崩溃,使用时请继承ApplicationException基类
5、业务逻辑上的数据尽量用if{}else{}过滤掉,不要靠throw new Exception()来处理
6、异常在程序中无法避免,合理使用避免程序崩溃才是唯一正确的道路
(以上结论仅代表个人观点)
public class TyhTest { private string msg; public TyhTest(string msg) { this.msg = msg; } } public class TyhException : ApplicationException { //这种写法是继承基类构造方法 public TyhException(string msg): base(msg) { } } class Program { static void Main(string[] args) { int max = 100; int j = 1; string str = "a"; //========== Stopwatch time1 = new Stopwatch(); time1.Start(); for (int i = 0; i < max; i++) { try { if (j > 0 && !string.IsNullOrEmpty(str)) throw new Exception("Exception异常"); } catch (Exception e) { } } time1.Stop(); Console.WriteLine("抛出Exception异常耗时:" + time1.ElapsedMilliseconds); //========== Stopwatch time2 = new Stopwatch(); time2.Start(); for (int i = 0; i < max; i++) { try { if (j > 0 && !string.IsNullOrEmpty(str)) throw new ApplicationException("Exception异常"); } catch (ApplicationException e) { } } time2.Stop(); Console.WriteLine("抛出ApplicationException异常耗时:" + time2.ElapsedMilliseconds); //========== Stopwatch time3 = new Stopwatch(); time3.Start(); for (int i = 0; i < max; i++) { try { if (j > 0 && !string.IsNullOrEmpty(str)) throw new TyhException("Exception异常"); } catch (Exception e) { } } time3.Stop(); Console.WriteLine("抛出自定义TyhException异常耗时:" + time3.ElapsedMilliseconds); //========== Stopwatch time4 = new Stopwatch(); time4.Start(); for (int i = 0; i < max; i++) { try { if (j > 0 && !string.IsNullOrEmpty(str)) { } else { } } catch (Exception e) { } } time4.Stop(); Console.WriteLine("不抛异常用IF判断耗时:" + time4.ElapsedMilliseconds); //========== Stopwatch time5 = new Stopwatch(); time5.Start(); for (int i = 0; i < max; i++) { try { var test = new TyhTest("创建对象"); } catch (Exception e) { } } time5.Stop(); Console.WriteLine("创建普通对象TyhTest耗时:" + time5.ElapsedMilliseconds); //========== Stopwatch time6 = new Stopwatch(); time6.Start(); for (int i = 0; i < max; i++) { try { var test = new Exception("创建异常对象"); } catch (Exception e) { } } time6.Stop(); Console.WriteLine("创建异常对象Exception耗时:" + time6.ElapsedMilliseconds); Console.ReadKey(); } }
(Stopwatch 不需要 new 很多个,代码复制粘贴的,请忽略,忽略,哈哈~)