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

下載本文檔

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

文檔簡介

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

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

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

8.1.1使用VisualStudio.NET錯誤報告

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

8.1.1使用VisualStudio.NET錯誤報告

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

8.1.2尋找邏輯錯誤

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

8.1.2尋找邏輯錯誤

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

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

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

2023/2/17C#程序設(shè)計實用教程

8.1.2尋找邏輯錯誤

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

8.1.2尋找邏輯錯誤

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

8.1.2尋找邏輯錯誤

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

8.1.3單步執(zhí)行程序

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

8.1.3單步執(zhí)行程序

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

8.1.3單步執(zhí)行程序

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

8.1.4設(shè)置斷點

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

8.1.4設(shè)置斷點

【例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#程序設(shè)計實用教程

8.1.4設(shè)置斷點

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

8.1.4設(shè)置斷點

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

8.1.4設(shè)置斷點

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

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

8.1.4設(shè)置斷點

單擊“逐語句”按鈕

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

8.1.4設(shè)置斷點

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

8.1.5在哪里設(shè)置斷點

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

8.1.5在哪里設(shè)置斷點

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

8.1.5在哪里設(shè)置斷點

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

8.2異常處理

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

8.2.1異常類

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

8.2.1異常類

2023/2/126C#程序設(shè)計實用教程

8.2.2異常處理

在C#中,使用try、catch和finally關(guān)鍵字定義異常代碼塊?!纠?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#程序設(shè)計實用教程

8.2.2異常處理

程序運行后,會報錯:

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

8.2.2異常處理

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

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#程序設(shè)計實用教程

8.2.2異常處理

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

8.2.2異常處理

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

8.2.2異常處理

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

2023/2/133C#程序設(shè)計實用教程

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#程序設(shè)計實用教程

8.2.2異常處理

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

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

8.3高質(zhì)量編碼標(biāo)準(zhǔn)

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

8.3.1好的編碼結(jié)構(gòu)

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

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

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

8.3.1好的編碼結(jié)構(gòu)

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

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

8.3.1好的編碼結(jié)構(gòu)

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

8.3.2好的注釋風(fēng)格

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

8.3.2好的注釋風(fēng)格

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

//半徑

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

8.3.2好的注釋風(fēng)格

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

8.3.2好的注釋風(fēng)格

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

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)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論