.NET中怎么對(duì)異常進(jìn)行處理

本篇文章給大家分享的是有關(guān).NET中怎么對(duì)異常進(jìn)行處理,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

黃龍網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站開(kāi)發(fā)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)2013年至今到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)

有些人認(rèn)為下面代碼就是一個(gè)catch的錯(cuò)誤用法:

catch(Exception e)
{
    throw e;
}

首先說(shuō)明,這不是一個(gè)錯(cuò)誤用法,但是通常來(lái)講,我們應(yīng)該避免這種代碼。然后要說(shuō)明的是,這段代碼有一個(gè)比較典型的作用就是改變異常出現(xiàn)的位置,也就是可以對(duì)某類(lèi)異常統(tǒng)一在一個(gè)位置處理。先看下面代碼:

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è)類(lèi)庫(kù)等
        int i = 1;
        return i;
    }

    private void openDB()
    {
        conn.Open();
    }

假設(shè)我們有一個(gè)公用方法叫openDB(),而很多方法中調(diào)用它,當(dāng)數(shù)據(jù)庫(kù)打開(kāi)失敗的時(shí)候,對(duì)于調(diào)用GetAllCount方法,異常將定位于conn.Open而如果調(diào)用GetAllCount2,那么異常定位于throw sex的位置,同時(shí)堆棧信息也有所不同,可以更快捷的找到調(diào)用方法的位置,也可在此位置進(jìn)行一些錯(cuò)誤恢復(fù)處理。尤其是我們編寫(xiě)一些底層類(lèi)庫(kù)的時(shí)候,比如Framework類(lèi)庫(kù)從不會(huì)把異常代碼定位到Framework類(lèi)庫(kù)內(nèi)部的某個(gè)方法上面。但是需要注意的是我們盡量避免捕獲異常而不返回,例如:

catch(){}

這樣的使用就是典型的錯(cuò)誤使用了,因?yàn)閷?duì)于Framework來(lái)講,任何時(shí)候系統(tǒng)都可能拋出一個(gè)StackOverflowException或者OutOfMemoryExcetpion而上面這段代碼則隱藏了這些異常,有時(shí)候則導(dǎo)致一些嚴(yán)重的問(wèn)題。

對(duì)于異常處理,在性能上有2點(diǎn)注意

***點(diǎn):在使用try/catch時(shí),如果不發(fā)生異常,那么幾乎可以忽略性能的損失。

關(guān)于這一點(diǎn),這里我們進(jìn)行一些深入分析,對(duì)此比較了解的可以跳過(guò)本節(jié)。首先,讓我們先看一下try/catch的IL表現(xiàn)。我們有2個(gè)方法,一個(gè)使用try/catch,而另一個(gè)未做任何處理:

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,是因?yàn)镮L是比較接近機(jī)器匯編,所以在IL中我們可以更清楚的了解代碼的執(zhí)行情況,對(duì)IL沒(méi)有興趣的可以跳過(guò)此節(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

這里我們只需關(guān)注紅字高亮的幾行即可。此處我們只關(guān)心try區(qū)塊,即未發(fā)生異常的時(shí)候,對(duì)于Test1來(lái)講,IL代碼多出了8個(gè)字節(jié)來(lái)保存catch的處理代碼,這一點(diǎn)對(duì)性能和資源幾乎是微不足道的。

我們看到當(dāng)Test1執(zhí)行到IL_000f或者IL_0013的時(shí)候,將數(shù)據(jù)出棧并使用leave.s退出try區(qū)塊轉(zhuǎn)向IL_001b地址,然后將數(shù)據(jù)入棧并返回。

對(duì)于Test2來(lái)講,執(zhí)行到IL_000e或者IL_0012的時(shí)候, 直接退出,并將數(shù)據(jù)入棧然后返回。

這里對(duì)幾個(gè)關(guān)鍵指令簡(jiǎn)單介紹一下

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

下面我們看代碼的實(shí)際運(yùn)行情況,新建一個(gè)控制臺(tái)Console程序,加入下面代碼:

static void Main(string[] args)
{
    int times = 1000000;    //我們將結(jié)果放大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++) ;  // 模擬長(zhǎng)時(shí)操縱
        if (a > b)
            return a;
        return b;
    }
    catch
    {
        return -1;
    }
}

static int Test2(int a, int b)
{
    for (int i = 0; i < 100; i++) ;  // 模擬長(zhǎng)時(shí)操縱
    if (a > b)
        return a;
    return b;
}

運(yùn)行后可以看到代碼的差異,通常在0.0001%的差別以內(nèi)。

第二點(diǎn):如果發(fā)生異常,那么引發(fā)或處理異常時(shí),將使用大量的系統(tǒng)資源和執(zhí)行時(shí)間。引發(fā)異常只是為了處理確實(shí)異常的情況,而不是為了處理可預(yù)知的事件或流控制。例如,如果方法參數(shù)無(wú)效,而應(yīng)用程序需要使用有效的參數(shù)調(diào)用方法,則可以引發(fā)異常。無(wú)效的方法參數(shù)意味著出現(xiàn)了異常情況。相反,用戶偶爾會(huì)輸入無(wú)效數(shù)據(jù),這是可以預(yù)見(jiàn)的,因此如果用戶輸入無(wú)效,則不要引發(fā)異常。在這種情況下,請(qǐng)?zhí)峁┲卦嚈C(jī)制以便用戶輸入有效輸入。

我們經(jīng)常需要將一個(gè)字符串轉(zhuǎn)換為int,比如將Request.QueryString["id"]這樣的字符串轉(zhuǎn)換為int,在asp.net 1.x時(shí)代,我們常使用下列方式:

try
{
    int id = Int32.Parse("123");
}
catch(){}

這樣的后果是如果出現(xiàn)轉(zhuǎn)換異常,你將不得不犧牲大量的系統(tǒng)資源來(lái)處理異常,即使你沒(méi)有編寫(xiě)任何異常處理代碼。

當(dāng)然你也可以編寫(xiě)大量的代碼來(lái)檢測(cè)和轉(zhuǎn)換字符串來(lái)替代try/catch方式,而從asp.net 2.0以后,框架將這個(gè)檢測(cè)轉(zhuǎn)換過(guò)程封裝到Int32.TryParse方法中,再也不用蹩腳的try/catch來(lái)處理了。

還要補(bǔ)充一點(diǎn),就是finally中的代碼是始終保證運(yùn)行的,所以留給大家一個(gè)問(wèn)題,下面代碼執(zhí)行后a的值是多少:

int a = 2;
try
{
    int i = Int32.Parse("s");
}
catch
{
    a = 1;
    return;
}
finally
{
    a = 3;
}

以上就是.NET中怎么對(duì)異常進(jìn)行處理,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

分享文章:.NET中怎么對(duì)異常進(jìn)行處理
本文URL:http://muchs.cn/article6/gdsoig.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站內(nèi)鏈、標(biāo)簽優(yōu)化、品牌網(wǎng)站制作、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化