第8章 調(diào)試與異常處理_第1頁
第8章 調(diào)試與異常處理_第2頁
第8章 調(diào)試與異常處理_第3頁
第8章 調(diào)試與異常處理_第4頁
第8章 調(diào)試與異常處理_第5頁
已閱讀5頁,還剩44頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

第8章調(diào)試與異常處理程序的開發(fā)過程難免會發(fā)生錯誤,在開發(fā)大型項目中,程序的調(diào)試是一個漫長的過程。本章將介紹在VS.NET開發(fā)環(huán)境下調(diào)試C#代碼的各種方法,包括使用IDE的調(diào)試環(huán)境、人工尋找邏輯錯誤的常用策略,以及程序的異常處理機制。2023/2/12C#程序設計實用教程

8.1程序調(diào)試技術

VS.NET開發(fā)環(huán)境提供了強大的代碼調(diào)試功能。本節(jié)將探討如何利用它來快速消滅代碼中的語法錯誤和邏輯錯誤。2023/2/13C#程序設計實用教程

8.1.1使用VisualStudio.NET錯誤報告

代碼中的Bugs主要分為兩種,一種是語法錯誤,另一種是邏輯錯誤。首先,來看如何使用VS.NET來解決第一類問題。語法錯誤是指程序員所輸入的指令違反了C#語言的語法規(guī)定,例如下面的表達式: Stringstr=’HelloWorld’;顯然,這里應該使用雙引號表示字符串變量。當使用VS.NET編譯代碼時,VS.NET會在“任務列表”窗口提示出現(xiàn)錯誤,如圖8-1所示。2023/2/14C#程序設計實用教程

8.1.1使用VisualStudio.NET錯誤報告

雙擊錯誤提示,VS.NET將自動將光標定位到出現(xiàn)錯誤的代碼中。除了上面介紹的這種明顯的語法錯誤之外,還有一些稍微復雜的語法錯誤。例如,試圖在類外訪問其私有成員,使用未賦值的變量等,都可以通過這種方式來解決。2023/2/15C#程序設計實用教程

8.1.2尋找邏輯錯誤

與語法錯誤相比,邏輯錯誤是更讓人頭痛的問題。邏輯錯誤是指代碼在語法上沒有錯誤,但是從程序的功能上看,代碼卻無法正確完成其功能。同樣可以使用VS.NET來尋找邏輯錯誤。在調(diào)試模式下運行程序時,VS.NET并非僅僅是給出最后的結果,還保留了應用程序所有的中間結果,即VS.NET知道代碼每一行都發(fā)生了什么。既然這樣,程序員就可以通過跟蹤這些中間結果,來發(fā)現(xiàn)Bug到底藏在哪里。為了便于介紹,首先給出一個含有邏輯錯誤的示例代碼如下:2023/2/16C#程序設計實用教程

8.1.2尋找邏輯錯誤

【例10-1】含有邏輯錯誤的示例。usingSystem;

namespaceExample_LogicError{ publicclassStudent { ///<summary> ///輸出10次:“我不敢了!”

///</summary> publicvoidPunish() { for(inti=0;i<=10;i++) { Console.WriteLine("我不敢了!"); } } }

2023/2/17C#程序設計實用教程

8.1.2尋找邏輯錯誤

///<summary> ///Class1的摘要說明。 ///</summary> classClass1 { ///<summary> ///應用程序的主入口點。 ///</summary> [STAThread] staticvoidMain(string[]args) { Students=newStudent(); s.Punish(); } }}2023/2/18C#程序設計實用教程

8.1.2尋找邏輯錯誤

代碼定義了一個學生類,其中有一個方法Punish(),希望輸出10次“我不敢了!”。然而,結果卻輸出11次。相信讀者已經(jīng)找到了Bug在哪里,就是for語句的循環(huán)語句: for(inti=0;i<=10;i++)中的“i<=10”,應當改為“i<10”。然而,在實際的開發(fā)中,邏輯錯誤往往沒有這么容易被發(fā)現(xiàn)。針對這個示例,下面來看如何使用VS.NET把Bug找出來。首先介紹如何配置VS.NET使其進入調(diào)試環(huán)境。2023/2/19C#程序設計實用教程

8.1.2尋找邏輯錯誤

想要跟蹤代碼,要把VS.NET配置為中斷模式。這時,需要把程序的輸出項選為Debug,操作很簡單:在VS.NET工具菜單的“啟動調(diào)試”按鈕后面,調(diào)整下拉框的內(nèi)容為Debug即可,如圖8-2所示。2023/2/110C#程序設計實用教程

8.1.3單步執(zhí)行程序

首先可以使用單步執(zhí)行來運行程序,然后跟蹤代碼的每一步代碼,最后找到Bug在哪里。想要單步執(zhí)行,可以使用快捷鍵F11,或者單擊菜單命令【調(diào)試】→【逐語句】。開始單步執(zhí)行后,程序?qū)⑹紫葧和T谥骱瘮?shù)的第一行,繼續(xù)使用快捷鍵F10或F11可以向下執(zhí)行。兩者的區(qū)別在于:單步執(zhí)行時,可以選擇是否路過一行代碼中所調(diào)用的方法,如果是,則使用F10;如果想要進入過程,進行更為細致的觀察,則需要使用F11。另外,當程序暫停以后,VS.NET的監(jiān)視窗口便可以顯示當前執(zhí)行位置的變量值情況,當使用F11單步Punish方法后,“監(jiān)視”窗口如圖8-3所示。2023/2/111C#程序設計實用教程

8.1.3單步執(zhí)行程序

監(jiān)視窗口有3列,分別顯示想要監(jiān)視的變量名稱、變量的值,以及變量的數(shù)據(jù)類型。如果想要監(jiān)視某個變量的值,可以在監(jiān)視窗口的“名稱”欄直接輸入這個值,也可以把這個值從代碼中選中,然后按住左鍵,直接拖放到監(jiān)視窗口中。另外,除監(jiān)視窗口之外,還有自動窗口和局部變量窗口。2023/2/112C#程序設計實用教程

8.1.3單步執(zhí)行程序

在本例中,需要執(zhí)行for語句的語句體,即把以下語句: Console.WriteLine("我不敢了!");執(zhí)行11次,因此需要在這里按11次F10,然后仔細觀察監(jiān)視窗口內(nèi)i的值。在最后一次的時候,將發(fā)現(xiàn)i值為10,這時便可以發(fā)現(xiàn)問題所在了。2023/2/113C#程序設計實用教程

8.1.4設置斷點

對于單步執(zhí)行,有時候?qū)τ谳^大規(guī)模程序的調(diào)試是顯然不可行的。在此,還有另一種方式來解決這個問題,就是使代碼暫停在程序員想要的地方,也就是設置斷點(Breakpoint)。先來看下面所示的代碼,這段代碼是求10以內(nèi)的素數(shù),運行結果如圖8-4所示。2023/2/114C#程序設計實用教程

8.1.4設置斷點

【例10-2】求出10以內(nèi)的素數(shù)。staticvoidMain(string[]args){inti,s;for(s=2;s<10;s++){for(i=2;i<s;i++){if(s%i!=0)break;}if(i>=s)Console.WriteLine("{0}是素數(shù)",s);elseConsole.WriteLine("{0}不是素數(shù)",s);} Console.Read();}2023/2/115C#程序設計實用教程

8.1.4設置斷點

由運行結果可知,這段代碼雖然沒有語法錯誤,但執(zhí)行出來的結果卻不正確。要判定問題出在哪里,就需要用VS2005中的調(diào)試工具來進行檢查。在此,通過設置斷點來解決此問題的調(diào)試。2023/2/116C#程序設計實用教程

8.1.4設置斷點

首先在程序可能出現(xiàn)問題的開始處設置斷點,使程序能夠在某一行程序上停下來。使用中斷的方法有以下幾種:在設置斷點時,首先把光標放置在想要程序需要暫停的地方,然后使用快捷鍵F9或者用鼠標單擊那一行的前邊界或者Ctrl+D+N或者單擊菜單命令【調(diào)試】→【新斷點】。如果使用后兩者進行設置斷點,將出現(xiàn)斷點屬性對話框,如圖8-5所示。2023/2/117C#程序設計實用教程

8.1.4設置斷點

該程序的斷點設置在外層循環(huán)體語句開始處,如圖8-6所示,用圓點來表示。單擊“啟動調(diào)試”按鈕

,或按下F5鍵,程序執(zhí)行到斷點處中斷,根據(jù)前面的運行結果,第1個數(shù)據(jù)結果是正確的,單擊“啟動調(diào)試”按鈕,使第1個數(shù)據(jù)輸出,程序停留在斷點處,開始執(zhí)行第2個數(shù)據(jù)的循環(huán)。2023/2/118C#程序設計實用教程

8.1.4設置斷點

單擊“逐語句”按鈕

或按下F11鍵,程序從斷點處逐語句執(zhí)行,黃色顯示當前要執(zhí)行的語句。當程序逐句執(zhí)行時,可以從“局部變量”窗口查看當前變量的值,在即時窗口檢查某個變量或表達式的值,還可以在即時窗口中執(zhí)行一些VisualStudio命令。選擇“調(diào)試”→“窗口”,打開“局部變量”窗口,如圖8-7所示,在這個窗口中,可以看到當前方法中的局部變量的值。打開“即時窗口”,如圖8-8所示,在這個窗口可以輸入命令,查看變量,或計算表達式的值。2023/2/119C#程序設計實用教程

8.1.4設置斷點

“即時窗口”是一個有用的調(diào)試工具,在提示符“>”狀態(tài)下,輸入字母,可以智能顯示相關的命令。通過調(diào)試,當s等于3時,內(nèi)層循環(huán)結束后,i的值應該為3,可見出現(xiàn)問題的原因在于內(nèi)循環(huán)中。單擊“停止調(diào)試”按鈕或按下Shift+F5組合鍵,停止程序運行。將錯誤語句修改為: if(s%i==0)break;則程序運行結果正確。2023/2/120C#程序設計實用教程

8.1.5在哪里設置斷點

在工程中,如何恰當?shù)卦O置斷點,以迅速地縮小Bug藏身之處,是非常重要的技術。在此簡單介紹常用的設置斷點策略。1.從大到小,逐步縮小范圍有時候,程序員很難判定錯誤到底出現(xiàn)在哪種方法、哪一行,這時,可以從外到內(nèi),從大到小,逐步縮小Bug所在的范圍。一方面,可以通過設置斷點,然后逐個過程執(zhí)行來實現(xiàn)。2023/2/121C#程序設計實用教程

8.1.5在哪里設置斷點

另一方面,還需要程序員理清代碼的邏輯結構,迅速判定Bug可能所在的位置,然后在相應的位置設置斷點進行驗證。2023/2/122C#程序設計實用教程

8.1.5在哪里設置斷點

2.注釋掉可能出錯的行另外一種比較有效的尋找Bug的策略是,注釋掉一部分代碼,然后運行程序,看其是否出錯。其實這也是縮小Bug所在范圍的一種策略,不同于使用斷點來實現(xiàn)。在注釋掉一部分代碼之后,運行程序,如果程序不再出現(xiàn)錯誤,那么很明顯,Bug就在注釋掉的代碼之中。但是反過來,如果注釋掉部分代碼后運行結果仍不正確,也不能說注釋掉的代碼肯定正確。2023/2/123C#程序設計實用教程

8.2異常處理

再熟練的程序員也不能說自己編寫的代碼沒有任何問題。可以說,代碼中異常陷阱無處不在,如數(shù)據(jù)庫連接失敗、IO錯誤、數(shù)據(jù)溢出、數(shù)組下標越界等。鑒于此,C#提供了異常處理機制,允許開發(fā)者捕捉程序運行時可能出現(xiàn)的異常。2023/2/124C#程序設計實用教程

8.2.1異常類

當代碼出現(xiàn)諸如被除數(shù)為零、分配空間失敗等錯誤時,就會自動創(chuàng)建異常對象,它們大多是C#異常類的實例。System.Exception類是異常類的基類,一般不要直接使用System.Exception,它沒有反映具體的異常信息,而使用是它的派生類。在C#中,經(jīng)常使用的異常類見表8-1。2023/2/125C#程序設計實用教程

8.2.1異常類

2023/2/126C#程序設計實用教程

8.2.2異常處理

在C#中,使用try、catch和finally關鍵字定義異常代碼塊?!纠?0-3】異常處理的示例。程序代碼如下:///<summary>///未使用異常處理機制示例///</summary>publicvoidtest_notry(){ int[]arr={0,1,2}; for(inti=0;i<=3;i++) //i==3時,越界了! { Console.WriteLine(arr[i]); }}2023/2/127C#程序設計實用教程

8.2.2異常處理

程序運行后,會報錯:

“未處理的異常:System.IndexOutOfRangeException:索引超出了數(shù)組界限。”2023/2/128C#程序設計實用教程

8.2.2異常處理

停止繼續(xù)運行。通過使用try-catch-finally語句處理后就可以妥善解決這個問題。將有可能發(fā)生異常的代碼放在try語句塊,處理try語句中出現(xiàn)的異常代碼放到catch語句塊,finally語句則是不管try語句中有沒有異常發(fā)生,最后都要執(zhí)行finally語句中的程序塊。2023/2/129C#程序設計實用教程

8.2.2異常處理

publicvoidtest_withtry(){ int[]arr={0,1,2}; try { for(inti=0;i<=3;i++) //i==3時,越界了! { Console.WriteLine(arr[i]); } } catch(Exceptione) { Console.WriteLine(e.Message); } finally { Console.WriteLine("Exittest_withtry()"); }}2023/2/130C#程序設計實用教程

8.2.2異常處理

說明:當在try{…}代碼塊中出現(xiàn)異常時,C#將自動轉向catch{…}代碼塊,并執(zhí)行其中的內(nèi)容。無論是否出現(xiàn)異常,程序都會執(zhí)行finally{…}中的代碼。try-catch-finally語句有三種形式:try-catchtry-catch-finallytry-finally通常情況下要將可能發(fā)生異常的多條代碼放入在try塊中,一個try塊必須有至少一個與之相關聯(lián)的catch塊或finally塊,單獨一個try塊是沒有意義的。2023/2/131C#程序設計實用教程

8.2.2異常處理

catch塊中包含的是出現(xiàn)異常時要執(zhí)行的代碼。一個try后面可以有零個以上的catch塊。如果try語句中沒有異常,則catch塊中代碼不會被執(zhí)行。catch后面括號放入希望捕獲的異常。當兩個catch語句的異常類有派生關系的時候,要將包括派生的異常類catch語句放到前面,包括基類的catch語句放置到后面。finally塊包含了一定要執(zhí)行的代碼,通常是一些資源釋放,關閉文件等代碼。2023/2/132C#程序設計實用教程

8.2.2異常處理

下面請看多catch語句的示例?!纠?0-4】含有多catch語句的示例。///<summary>///使用異常處理機制示例///</summary>publicvoidtest_withtry_mulcatch(){int[]arr={0,1,2};

2023/2/133C#程序設計實用教程

8.2.2異常處理

try{for(inti=0;i<=3;i++) //i==3時,越界了!{Console.WriteLine(arr[i]);}

}catch(IndexOutOfRangeExceptione){Console.WriteLine(e.Message);}catch(Exceptione){Console.WriteLine(e.Message);}finally{Console.WriteLine("Exittest_withtry_mulcatch()");}}2023/2/134C#程序設計實用教程

8.2.2異常處理

運行結果如下:索引超出了數(shù)組界限。Exittest_withtry_mulcatch()第一個catch語句捕獲異常是IndexOutOfRangeException,表示使用了下標小于零或超出數(shù)組下標界限的數(shù)組時引發(fā)異常,第二個catch語句捕獲異常是Exception,它是所有異常類的基類。最終執(zhí)行的是第二個catch語句。但是,如果將在代碼中現(xiàn)有的第二個catch語句作為第一個catch語句來使用,程序編譯不能通過,將提示:“上一個

catch子句已經(jīng)捕獲了此類型或超類型 (“System.Exception”)的所有異常”。2023/2/135C#程序設計實用教程

8.3高質(zhì)量編碼標準

一般來說,程序總是有可能出現(xiàn)錯誤的。不過,好的編碼方式可以大大降低常見錯誤出現(xiàn)的機會。8.3.1好的編碼結構對比下面兩段代碼,它們的功能相同,都是定義了一個圓類,并包含求面積的方法。2023/2/136C#程序設計實用教程

8.3.1好的編碼結構

代碼段A(結構良好的圓類實現(xiàn)):publicclassCircle{publicdoubledblRadius;

publicCircle(double_dblRadius){this.dblRadius=_dblRadius;}

publicdoubleGetArea(){returndblRadius*dblRadius*3.1415926;}}2023/2/137C#程序設計實用教程

8.3.1好的編碼結構

代碼段B(結構混亂的圓類實現(xiàn)):publicclassCircle{publicdoubledblRadius;publicCircle(double_dblRadius){this.dblRadius=_dblRadius;}

publicdoubleGetArea(){returndblRadius*dblRadius*3.1415926;}}相信,在不做任何解釋的情況下,讀者是能看明白代碼A的內(nèi)容,因為它縮進結構良好,體現(xiàn)了清晰的邏輯結構。而代碼B呢?要想看明白,則很困難。2023/2/138C#程序設計實用教程

8.3.1好的編碼結構

說明:縮進應使用Tab鍵,而不要使用空格鍵。由上述可以看出,良好的代碼層次結構以及清晰的代碼邏輯結構,可以很大程序上提高代碼的質(zhì)量,一方面可以降低程序員出錯的可能性,另一方面,在代碼出現(xiàn)錯誤的時候也較容易尋找到錯誤所在。2023/2/139C#程序設計實用教程

8.3.2好的注釋風格

良好的注釋可以大大提高代碼的可閱讀性,另外在編寫程序時,還可以幫助程序員具有更為清晰的編程思路。同樣,比較8.3.1中的代碼段A與下面的代碼段C。2023/2/140C#程序設計實用教程

8.3.2好的注釋風格

代碼段C(具有良好注釋的圓類實現(xiàn)):///<summary>///圓類///</summary>publicclassCircle{publicdoubledblRadius;

//半徑

///<summary>///構造函數(shù)///</summary>///<paramname="_dblRadius">半徑</param>publicCircle(double_dblRadius){this.dblRadius=_dblRadius;}2023/2/141C#程序設計實用教程

8.3.2好的注釋風格

///<summary>///求圓的面積///</summary>///<returns>面積</returns>publicdoubleGetArea(){returndblRadius*dblRadius*3.1415926;}}2023/2/142C#程序設計實用教程

8.3.2好的注釋風格

顯而易見,有了注釋之后,完全沒有必要對這段代碼進行解釋了,讀者一定能夠看懂。另外,VS.NET提供了良好的自動注釋功能,在方法或者類的前面用“///”添加注釋時,會自動生成大量的注釋格式,只需要在相應的位置添入注釋項即可。在此,推薦盡量使用“///”對類或方法進行注釋,這樣做還有另外一個好處,當引用這個類或者方法時,VS.NET會自動提示注釋的內(nèi)容。2023/2/143C#程序設計實用教程

8.3.3好的命名規(guī)范

在編碼中,常常使用到的命名規(guī)范有:Pascal命名規(guī)范:每個單詞的首字母大寫,例如ProductType。Camel命名規(guī)范:首個單詞的首字母小寫,其余單詞的首字母大寫,例如productType。在C#中,推薦的命名規(guī)范如下:(1)類名使用Pascal命名規(guī)范,如:pu

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論