【所见即所得】Try Catch 效率问题

 

 

 

一、问题引入 

     维护老项目,看到下面一个函数:

    /// <summary>
    /// 从ViewState中获取某个属性的值。如果该属性不存在,返回空字符串。

    /// </summary>
    /// <param name="PropertyName">属性名称</param>
    /// <returns>属性值(属性不存在时返回空字符串)</returns>
    protected string GetViewState(string PropertyName)
    {
        try
        {
            return ViewState[PropertyName].ToString();
        }
        catch (NullReferenceException)
        {
            return "";
        }
    }

二、问题分析

     代码功能很明显“从ViewState中获取某个属性的值。如果该属性不存在,返回空字符串。”。看起来也很整洁,想起以前在园子类看到的讨论try-catch的性能问题,基本上已经有定论。自己想验证下:

    测试的类代码如下:

 public  class TryCatch {
      static Stopwatch sw = new Stopwatch();
       /// <summary>
       /// 带有finally的try引发异常来完成字符串赋值
       /// </summary>
       /// <param name="str">传入参数,调用的时候会是null</param>
       /// <returns></returns>
      public static string TryCatchwithFinally(string str) {
          sw.Reset();
          sw.Start();
          try {
              return str.ToString();
          }
          catch (NullReferenceException) {
              return "exception!";
          }
          finally {
              sw.Stop();
              Console.WriteLine("发生exception,带finally的trycatch用时{0}毫秒",sw.ElapsedMilliseconds);
          }
      }
      /// <summary>
      /// 带有finally的try不引发异常通过ifelse来完成字符串赋值
      /// </summary>
      /// <param name="str">传入参数,调用的时候会是null</param>
      /// <returns></returns>
      public static string IfElsewithFinally(string str) {
          sw.Reset();
          sw.Start();
          try {
              if (!string.IsNullOrEmpty(str)) {
                  return str.ToString();
              }
              else {
                  return "";
              }

          }
          catch (NullReferenceException) {
              return "exception!";
          }
          finally {
              sw.Stop();
              Console.WriteLine("不发生exception,带finally得ifelse用时{0}毫秒", sw.ElapsedMilliseconds);
          }
      }
      /// <summary>
      ///  不带有finally的try不引发异常通过ifelse来完成字符串赋值
      /// </summary>
      /// <param name="str">传入参数,调用的时候会是null</param>
      /// <returns></returns>
      public static string IfElse(string str) {
          sw.Reset();
          sw.Start();
          try {
              if (!string.IsNullOrEmpty(str)) {
                  return str.ToString();
              }
              else {
                  sw.Stop();
                  Console.WriteLine("发生exception,ifelse用时{0}毫秒", sw.ElapsedMilliseconds);
                  return "";
              }
          }
          catch (NullReferenceException) {
             
              return "exception!";
        
          }
        
      }
      /// <summary>
      /// 不带有finally的try引发异常来完成字符串赋值
      /// </summary>
      /// <param name="str">传入参数,调用的时候会是null</param>
      /// <returns></returns>
      public static string Trycatch(string str) {
          sw.Reset();
          sw.Start();
          try {
              return str.ToString();
          }
          catch (NullReferenceException) {
              sw.Stop();
              Console.WriteLine("发生exception,trycatch用时{0}毫秒", sw.ElapsedMilliseconds);
              return "exception!";
             
          }

      }
    }

主调函数如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FMS_Refacting.try_catch;


namespace Fibo.ConsoleApplication {
        class Program {
            static void Main(string[] args) {

                TryCatch.IfElsewithFinally(null);//1
                TryCatch.Trycatch(null);//2
                TryCatch.TryCatchwithFinally(null);//3               
                TryCatch.IfElse(null);//3
                Console.ReadKey();

            }
        
    }
   
}

 

   结果如下:

image

 

  将主调函数main中4个语句调换顺序,得到的测试结果大体相同。也就是,用trycatch实现逻辑(简单的)耗时在100毫秒(这个有可能不太准确,不过大约在100倍左右)以上,而ifelse基本不耗时。同一类型的异常被第一次抛出的时候性能会下降很多,而在后续抛出则基本没有影响,CLR在异常处理的这一点进行了强大的优化。

  同时finally中如果没有什么复杂的逻辑的话并不会影响性能。

  下面是 imfunny兄一些高见:

这个结论貌似不对的。
和复杂的逻辑其实没有什么关系。所以楼主改正下呢。
缺少了finally 实际上就缺少了ret的分界表,于是就导致了对异常类型以及异常类型的匹配过程。而这个部分才是耗时的。
 

 

finally 即使有复杂的逻辑也没有关系。这个其实是代码执行的时间。比如有些对资源进行回收导致的代的回收等。
实际上catch过程可用可不用。如果不用可以再Application扑捉到嘿嘿。

  当然为了美观和可读性,ifelse可以用?:和??来代替。

 

三、所得

    对trycatch的运用;只控制异常,不控制逻辑。

    坚信:过度的设计是犯罪,不设计更是犯罪!

    知道了,并运用了Stopwatch类;

   以后继续所见即所得的学习!

 

PS:  在园子里面找到了金大侠的大作:深入理解CLR异常处理机制(http://www.cnblogs.com/bitfan/archive/2009/12/03/1616550.html)。从原理上讲的已经很透彻了。

posted on 2012-01-13 10:32  付之一笑  阅读(4384)  评论(33编辑  收藏  举报

导航