〖 作者:不详 〗〖 大小: 2k 〗〖 发布日期: 2006-05-30 〗〖 浏览: 415 〗 | ||||
现代的编程语言如
c++ , java , c#
等都十分重视对错误的防止、处理,在这儿我就讲一下在
c#
里的排错、纠错,希望大家能从中学到一些有用的东西,希望以后不会再听到文章开头那句话。
debug 最理想的状态是什么?这个不用我说,那就是 defect free ,没有 bug ,呵呵。但早有人说了,没有 bug 那还叫程序吗? win2000 还 60000 多个 bug 呢。所以我们要做到的是尽量防止 bug , bug 出现后能迅速定位问题所在,修正这个 bug 。 .net 提供了很丰富的 debug 手段,除了一些 debug 相关的 nampespace , c# 语言本身也有相关的内容存在。常用的有条件编译、 try/catch 、 trace 以及断言 (Assert) 等,如果你能熟练掌握这些手段,综合运用,那么 debug 将不再是一场恶梦,也不会像现在这样出现一点儿问题就满论坛追着人问: “ 我这儿又出错了,为什么呀? ” 。下面我将分别讲一下这些手段的运用。 一、捕捉异常 (try / catch /finally) 这个我不用说,大家都清楚它的作用,就是捕捉程序中所有可能导致错误的异常,然后加入自己的处理措施,并且使程序继续运行,而如果不捕捉异常的话,程序将会终止,简单的把错误信息发送给客户。 所以,在进行所有可能出现错误的操作时都应该捕捉异常,象下面这个例子,捕捉数据库操作可能出现的异常。 /// <summary> /// 取得数据库连接 /// </summary> /// <param name="a_strDatabase"> 数据库名 </param> /// <param name="oa_objConnection"> 输出参数,空数据库连接 </param> public void GetConnection(string a_strDatabase , out SqlConnection oa_objConnection) { oa_objConnection = null ; string strConnStr = ""; try { strConnStr = "server=" + m_objIni.GetProperty("server") + ";uid=" + m_objIni.GetProperty("uid") + ";pwd=" + m_objIni.GetProperty("password") + ";database=" + a_strDatabase ; oa_objConnection = new SqlConnection(strConnStr) ; oa_objConnection.Open() ; //log it m_objLog.Write(" 数据库连接 ok") ; } catch(SqlException e) { //log it m_objLog.Write(" 数据库 映龃 ? , e) ; #if DEBUG Console.WriteLine(e.ToString()) ; #endif//DEBUG throw(e) ; } } }//end class 二、条件编译 java 不提供条件编译,这是我觉得 java 不好的一个原因之一,所以在写 java 时都是自己写一个类来实现条件编译。那么,什么是条件编译呢?就是当符合某一条件时编译,不符合时就不编译,这就方便了 debug 。我们经常遇到这种情况,在某一过程或方法里我们想要知道某个变量的值,比较常用的方法是在页面或控制台输出这个变量的值,已确定是否是自己希望的值,但如果没有条件编译的话,但当你发布发行版本时需要手工删掉这些输出语句,费时、费力,并且容易出错,而如果有条件编译,那就方便多了。看下面这个例子: /// <summary> /// 初始化 /// </summary> private void Initialize() { try { m_objConnManager = new ConnManager(m_strIniFilePath , "./config/newsdata.ini") ; log = new Log("./logs/newserver.log") ; } catch(Exception e) { #if DEBUG Console.WriteLine(" 初始化 " + e.Message) ; #endif//DEBUG throw(new Exception(" 初始化 " + e.Message)) ; } } 注意到其中的 #if DEBUG 那几句吗?它的作用就是当 DEBUG 时,在控制台输出异常信息,以便你马上知道出现什么错误,而当不是 DEBUG 时,那句就不会被编译。 三、断言 (Assert) 断言真是一个值得大书特书的好东西,但可惜的是 80% 的程序员尤其是 web 程序员不用它,甚至根本就没听说过。很难给断言下一个定义,如果要详细说它的好处,简直都可以写一本书了。简单地说,断言就是在应该是正确的地方加一个判断已确定它真的正确(这话有些拗口,下面我会详细解释),它的作用就是确保你的程序按照预计的目标正常运行,并且能够帮助你迅速定位错误原因。断言的机制很简单,就象 c# 里的断言方法 System.Diagnostics.Debug.Assert 的定义,判断一个条件是否成立,如果不成立的话就显示一条信息。看起来很简单,真的能起那么大作用吗?让我们看下边这个例子。 /// <summary> /// 存取 m_strID 的属性 /// </summary> public string ID { get { return this.m_strID ; } set { #if DEBUG // 断言 Debug.Assert(value.Length % 2 == 0 , " 分类 id 长度必须为偶数 ") ; #endif this.m_strID = value ; } }//end method 这是个很简单的方法,就是为了存取 m_strID 这个成员变量的值,这个 m_strID 是个利用编码规则实现树形结构的字符串成员变量,就像这样: 010213 ,两位为一间隔,通过它的长度和编码规则可以很容易得到它位于第几层,它的父节点的 id 等等。因为两位数为一间隔,所以这个字符串的长度必须是个偶数。 看到 Debug.Assert 那句吗?它的作用就是判断这个字符串的长度是不是偶数,如果不是,则谈出一个对话框来显示 " 分类 id 长度必须为偶数 " 。或许你会说看不出它有什么作用,不就是判断一个值符不符合要求吗。本来这个程序都是你自己写的,所以你给这个 m_strID 赋值时应该知道这个长度为偶数的限制,一般情况下应该都是正确的,好,现在让我们假设这么一种情况,由于某种原因,你忘记了这个限制,而把一个长度是奇数的字符串赋给这个变量,而这时虽然有问题但程序并不报错,继续运行,当过了很远时,这个错误显露出来,使整个程序崩溃或最终结果不正确,这时即使程序报错也是在离产生这个错误的真正原因很远的地方,或者干脆就不报错,这是你要找到错误的原因就很困难了,可能要花费几小时甚至几天的时间,而如果当时你加了断言,运行到这里的时候就会终止,告诉你错误的原因,也就避免了后面出现的问题以及你为纠正这个问题所付出的时间和精力。 怎么样,现在是不是对断言有了一定的了解,并且有一些兴趣呢?试一下吧,慢慢的你会感受到它的威力。另外需要说的一点是断言是为了辅助 deubg 的,而不是进行错误处理的,所以一般把它和条件编译结合使用,只有当编程、测试时才使用断言,而当发行正是版本时应该去掉断言,因为毕竟它是要影响效率的。 四、日志 (log) 程序记不记日志恐怕是区分传统程序员和 web 程序员最好的标志了。大多数应用程序都记日志,而几乎所有的 web 程序都不记日志,呵呵。其实日志也是一个特别有用的东西,如果不记录日志,那很可能系统发生了什么、出现什么情况你都不清楚,尤其是时间一长,更容易出现这种情况。所以,养成良好的习惯,让你的程序写 log 吧。 当然,除了上述这些,还有很多东西,如跟踪( trace )单步调试等等,你可以自己看一下资料。 方法我都讲了,用不用就是你的问题了,呵呵。 |
如何更好更快的debug
最新推荐文章于 2023-06-28 18:08:22 发布