本篇文章給大家分享的是有關.NET中怎么對異常進行處理,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
黃龍網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、APP開發(fā)、響應式網(wǎng)站開發(fā)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)2013年至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設就選創(chuàng)新互聯(lián)。
有些人認為下面代碼就是一個catch的錯誤用法:
catch(Exception e) { throw e; } |
首先說明,這不是一個錯誤用法,但是通常來講,我們應該避免這種代碼。然后要說明的是,這段代碼有一個比較典型的作用就是改變異常出現(xiàn)的位置,也就是可以對某類異常統(tǒng)一在一個位置處理。先看下面代碼:
public int GetAllCount2() { try { openDB(); int i = 1; return i; } catch (SqlException sex) { throw sex; } catch (Exception ex) { throw ex; } } public int GetAllCount() { openDB(); // 這里也可能是微軟企業(yè)類庫等 int i = 1; return i; } private void openDB() { conn.Open(); } |
假設我們有一個公用方法叫openDB(),而很多方法中調用它,當數(shù)據(jù)庫打開失敗的時候,對于調用GetAllCount方法,異常將定位于conn.Open而如果調用GetAllCount2,那么異常定位于throw sex的位置,同時堆棧信息也有所不同,可以更快捷的找到調用方法的位置,也可在此位置進行一些錯誤恢復處理。尤其是我們編寫一些底層類庫的時候,比如Framework類庫從不會把異常代碼定位到Framework類庫內部的某個方法上面。但是需要注意的是我們盡量避免捕獲異常而不返回,例如:
catch(){} |
這樣的使用就是典型的錯誤使用了,因為對于Framework來講,任何時候系統(tǒng)都可能拋出一個StackOverflowException或者OutOfMemoryExcetpion而上面這段代碼則隱藏了這些異常,有時候則導致一些嚴重的問題。
對于異常處理,在性能上有2點注意
***點:在使用try/catch時,如果不發(fā)生異常,那么幾乎可以忽略性能的損失。
關于這一點,這里我們進行一些深入分析,對此比較了解的可以跳過本節(jié)。首先,讓我們先看一下try/catch的IL表現(xiàn)。我們有2個方法,一個使用try/catch,而另一個未做任何處理:
static int Test1(int a, int b) { try { if (a > b) return a; return b; } catch { return -1; } } static int Test2(int a, int b) { if (a > b) return a; return b; } |
使用ILDasm工具查看,IL代碼分別如下:(這里之所以引入IL,是因為IL是比較接近機器匯編,所以在IL中我們可以更清楚的了解代碼的執(zhí)行情況,對IL沒有興趣的可以跳過此節(jié))
.method private hidebysig static int32 Test1(int32 a, int32 b) cil managed { // 代碼大小 30 (0x1e) .maxstack 2 .locals init ([0] int32 CS$1$0000, [1] bool CS$4$0001) IL_0000: nop .try { IL_0001: nop IL_0002: ldarg.0 IL_0003: ldarg.1 IL_0004: cgt IL_0006: ldc.i4.0 IL_0007: ceq IL_0009: stloc.1 IL_000a: ldloc.1 IL_000b: brtrue.s IL_0011 IL_000d: ldarg.0 IL_000e: stloc.0 IL_000f: leave.s IL_001b IL_0011: ldarg.1 IL_0012: stloc.0 IL_0013: leave.s IL_001b } // end .try catch [mscorlib]System.Object { IL_0015: pop IL_0016: nop IL_0017: ldc.i4.m1 IL_0018: stloc.0 IL_0019: leave.s IL_001b } // end handler IL_001b: nop IL_001c: ldloc.0 IL_001d: ret } // end of method Program::Test1
Test2
.method private hidebysig static int32 Test2(int32 a, int32 b) cil managed { // 代碼大小 22 (0x16) .maxstack 2 .locals init ([0] int32 CS$1$0000, [1] bool CS$4$0001) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: cgt IL_0005: ldc.i4.0 IL_0006: ceq IL_0008: stloc.1 IL_0009: ldloc.1 IL_000a: brtrue.s IL_0010 IL_000c: ldarg.0 IL_000d: stloc.0 IL_000e: br.s IL_0014 IL_0010: ldarg.1 IL_0011: stloc.0 IL_0012: br.s IL_0014 IL_0014: ldloc.0 IL_0015: ret } // end of method Program::Test2
這里我們只需關注紅字高亮的幾行即可。此處我們只關心try區(qū)塊,即未發(fā)生異常的時候,對于Test1來講,IL代碼多出了8個字節(jié)來保存catch的處理代碼,這一點對性能和資源幾乎是微不足道的。
我們看到當Test1執(zhí)行到IL_000f或者IL_0013的時候,將數(shù)據(jù)出棧并使用leave.s退出try區(qū)塊轉向IL_001b地址,然后將數(shù)據(jù)入棧并返回。
對于Test2來講,執(zhí)行到IL_000e或者IL_0012的時候, 直接退出,并將數(shù)據(jù)入棧然后返回。
這里對幾個關鍵指令簡單介紹一下
nop do noting
stloc.0 Pop value from stack into local variable 0.
ldloc.0 Load local variable 0 onto stack.
br.s target branch to target, short form
leave.s target Exit a protected region of code, short form
下面我們看代碼的實際運行情況,新建一個控制臺Console程序,加入下面代碼:
static void Main(string[] args) { int times = 1000000; //我們將結果放大100,0000倍 long l1, l2,l3,l4, s1, s2; Console.WriteLine("Press any key to continue"); Console.Read(); for (int j = 0; j < 10; j++) { l1 = DateTime.Now.Ticks; for (int i = 0; i < times; i++) Test2(2, 4); l2 = DateTime.Now.Ticks; s1 = l2 - l1; Console.WriteLine("time spent:" + s1); l3 = DateTime.Now.Ticks; for (int i = 0; i < times; i++) Test1(2, 4); l4 = DateTime.Now.Ticks; s2 = l4 - l3; Console.WriteLine("time spent:" + s2); Console.WriteLine("difference:" + (s2 - s1) + ", rate:" + (float)(s2 - s1) / s1 / times); } } static int Test1(int a, int b) { try { for (int i = 0; i < 100; i++) ; // 模擬長時操縱 if (a > b) return a; return b; } catch { return -1; } } static int Test2(int a, int b) { for (int i = 0; i < 100; i++) ; // 模擬長時操縱 if (a > b) return a; return b; }
運行后可以看到代碼的差異,通常在0.0001%的差別以內。
第二點:如果發(fā)生異常,那么引發(fā)或處理異常時,將使用大量的系統(tǒng)資源和執(zhí)行時間。引發(fā)異常只是為了處理確實異常的情況,而不是為了處理可預知的事件或流控制。例如,如果方法參數(shù)無效,而應用程序需要使用有效的參數(shù)調用方法,則可以引發(fā)異常。無效的方法參數(shù)意味著出現(xiàn)了異常情況。相反,用戶偶爾會輸入無效數(shù)據(jù),這是可以預見的,因此如果用戶輸入無效,則不要引發(fā)異常。在這種情況下,請?zhí)峁┲卦嚈C制以便用戶輸入有效輸入。
我們經(jīng)常需要將一個字符串轉換為int,比如將Request.QueryString["id"]這樣的字符串轉換為int,在asp.net 1.x時代,我們常使用下列方式:
try { int id = Int32.Parse("123"); } catch(){} |
這樣的后果是如果出現(xiàn)轉換異常,你將不得不犧牲大量的系統(tǒng)資源來處理異常,即使你沒有編寫任何異常處理代碼。
當然你也可以編寫大量的代碼來檢測和轉換字符串來替代try/catch方式,而從asp.net 2.0以后,框架將這個檢測轉換過程封裝到Int32.TryParse方法中,再也不用蹩腳的try/catch來處理了。
還要補充一點,就是finally中的代碼是始終保證運行的,所以留給大家一個問題,下面代碼執(zhí)行后a的值是多少:
int a = 2; try { int i = Int32.Parse("s"); } catch { a = 1; return; } finally { a = 3; } |
以上就是.NET中怎么對異常進行處理,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享文章:.NET中怎么對異常進行處理
本文URL:http://m.newbst.com/article6/gdsoig.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供ChatGPT、網(wǎng)站設計公司、網(wǎng)站內鏈、標簽優(yōu)化、品牌網(wǎng)站制作、服務器托管
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)