亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

<展現C#> 第七章 異常處理

2019-11-18 22:06:49
字體:
來源:轉載
供稿:網友
第七章   異常處理

    通用語言運行時(CLR)具有的一個很大的優勢為,異常處理是跨語言被標準化的。一個在C#中所引發的異??梢栽赩isual Basic客戶中得到處理。不再有 HRESULTs  或者 ISupportErrorInfo 接口。
    盡管跨語言異常處理的覆蓋面很廣,但這一章完全集中討論C#異常處理。你稍為改變編譯器的溢出處理行為,接著有趣的事情就開始了:你處理了該異常。要增加更多的手段,隨后引發你所創建的異常。

7.1  校驗(checked)和非校驗(unchecked)語句
    當你執行運算時,有可能會發生計算結果超出結果變量數據類型的有效范圍。這種情況被稱為溢出,依據不同的編程語言,你將被以某種方式通知——或者根本就沒有被通知。(C++程序員聽起來熟悉嗎?)
     那么,C#如何處理溢出的呢? 要找出其默認行為,請看我在這本書前面提到的階乘的例子。(為了方便其見,前面的例子再次在清單 7.1 中給出)

清單 7.1     計算一個數的階乘

1: using System;
2:
3: class Factorial
4: {
5:  public static void Main(string[] args)
6:  {
7:   long nFactorial = 1;
8:   long nComputeTo = Int64.Parse(args[0]);
9:
10:   long nCurDig = 1;
11:   for (nCurDig=1;nCurDig <= nComputeTo; nCurDig++)
12:    nFactorial *= nCurDig;
13:
14:   Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
15:  }
16: }

    當你象這樣使用命令行執行程序時
    factorial 2000

    結果為0,什么也沒有發生。因此,設想C#默默地處理溢出情況而不明確地警告你是安全的。
     通過給整個應用程序(經編譯器開關)或于語句級允許溢出校驗,你就可以改變這種行為。以下兩節分別解決一種方
案。
7.1.1 給溢出校驗設置編譯器
    如果你想給整個應用程序控制溢出校驗,C#編譯器設置選擇是正是你所要找的。默認地,溢出校驗是禁用的。要明確
地要求它,運行以下編譯器命令:
csc factorial.cs /checked+

    現在當你用2000參數執行應用程序時,CLR通知你溢出異常(見圖 7.1)。

圖 7.1 允許了溢出異常,階乘代碼產生了一個異常。

  按OK鍵離開對話框揭示了異常信息:
Exception occurred: System.OverflowException
  at Factorial.Main(System.String[])

  現在你了解了溢出條件引發了一個 System.OverflowException異常。下一節,在我們完成語法校驗之后,如何捕獲并
處理所出現的異常?
7.1.2 語法溢出校驗
  如果你不想給整個應用程序允許溢出校驗,僅給某些代碼段允許校驗,你可能會很舒適。對于這種場合,你可能象清
單7.2中顯示的那樣,使用校驗語句。

清單 7.2  階乘計算中的溢出校驗

1: using System;
2:
3: class Factorial
4: {
5:  public static void Main(string[] args)
6:  {
7:   long nFactorial = 1;
8:   long nComputeTo = Int64.Parse(args[0]);
9:
10:   long nCurDig = 1;
11:
12:   for (nCurDig=1;nCurDig <= nComputeTo; nCurDig++)
13:    checked { nFactorial *= nCurDig; }
14:
15:   Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
16:  }
17: }

  甚至就如你運用標志 checked-編譯了該代碼,在第13行中,溢出校驗仍然會對乘法實現檢查。錯誤信息保持一致。

  顯示相反行為的語句是非校驗(unchecked )。甚至如果允許了溢出校驗(給編譯器加上checked+標志),被
unchecked 語句所括住的代碼也將不會引發溢出異常:

unchecked
{
nFactorial *= nCurDig;
}
  
    

7.2  異常處理語句
  既然你知道了如何產生一個異常(你會發現更多的方法,相信我),仍然存在如何處理它的問題。如果你是一個 C++
WIN32 程序員,肯定熟悉SEH(結構異常處理)。你將從中找到安慰,C#中的命令幾乎是相同的,而且它們也以相似的方
式運作。

The following three sections introduce C#'s exception-handling statements:
  以下三節介紹了C#的異常處理語句:

。用 try-catch 捕獲異常
。用try-finally 清除異常
。用try-catch-finally 處理所有的異常

7.2.1  使用 try 和 catch捕獲異常
  你肯定會對一件事非常感興趣——不要提示給用戶那令人討厭的異常消息,以便你的應用程序繼續執行。要這樣,你
必須捕獲(處理)該異常。
    這樣使用的語句是try 和 catch。try包含可能會產生異常的語句,而catch處理一個異常,如果有異常存在的話。清
單7.3 用try 和 catch為OverflowException 實現異常處理。

   清單7.3  捕獲由Factorial Calculation引發的OverflowException 異常

1: using System;
2:
3: class Factorial
4: {
5:  public static void Main(string[] args)
6:  {
7:   long nFactorial = 1, nCurDig=1;
8:   long nComputeTo = Int64.Parse(args[0]);
9:
10:   try
11:   {
12:    checked
13:    {
14:     for (;nCurDig <= nComputeTo; nCurDig++)
15:      nFactorial *= nCurDig;
16:    }
17:   }
18:   catch (OverflowException oe)
19:   {
20:    Console.WriteLine("Computing {0} caused an overflow exception", nComputeTo);
21:    return;
22:   }
23:
24:   Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
25:  }
26: }

    為了說明清楚,我擴展了某些代碼段,而且我也保證異常是由checked 語句產生的,甚至當你忘記了編譯器設置時。
    正如你所見,異常處理并不麻煩。你所有要做的是:在try語句中包含容易產生異常的代碼,接著捕獲異常,該異常在
這個例子中是OverflowException類型。無論一個異常什么時候被引發,在catch段里的代碼會注意進行適當的處理。
    如果你不事先知道哪一種異常會被預期,而仍然想處于安全狀態,簡單地忽略異常的類型。

try
{
...
}
catch
{
...
}

    但是,通過這個途徑,你不能獲得對異常對象的訪問,而該對象含有重要的出錯信息。一般化異常處理代碼象這樣:

try
{
...
}
catch(System.Exception e)
{
...
}

    注意,你不能用ref或out 修飾符傳遞 e 對象給一個方法,也不能賦給它一個不同的值。

7.2.2  使用 try 和 finally 清除異常
    如果你更關心清除而不是錯誤處理, try 和 finally 會獲得你的喜歡。它不僅抑制了出錯消息,而且所有包含在
finally 塊中的代碼在異常被引發后仍然會被執行。
    盡管程序不正常終止,但你還可以為用戶獲取一條消息,如清單 7.4 所示。

    清單 7.4  在finally 語句中處理異常

1: using System;
2:
3: class Factorial
4: {
5:  public static void Main(string[] args)
6:  {
7:   long nFactorial = 1, nCurDig=1;
8:   long nComputeTo = Int64.Parse(args[0]);
9:   bool bAllFine = false;
10:
11:   try
12:   {
13:    checked
14:    {
15:     for (;nCurDig <= nComputeTo; nCurDig++)
16:      nFactorial *= nCurDig;
17:    }
18:    bAllFine = true;
19:   }
20:   finally
21:   {
22:    if (!bAllFine)
23:     Console.WriteLine("Computing {0} caused an overflow exception", nComputeTo);
24:    else
25:     Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
26:   }
27:  }
28: }

    通過檢測該代碼,你可能會猜到,即使沒有引發異常處理,finally也會被執行。這是真的——在finally中的代碼總
是會被執行的,不管是否具有異常條件。為了舉例說明如何在兩種情況下提供一些有意義的信息給用戶, 我引進了新變量
bAllFine。bAllFine告訴finally 語段,它是否是因為一個異?;蛘邇H是因為計算的順利完成而被調用。
    作為一個習慣了SEH程序員,你可能會想,是否有一個與__leave 語句等價的語句,該語句在C++中很管用。如果你還
不了解,在C++中的__leave 語句是用來提前終止 try  語段中的執行代碼,并立即跳轉到finally 語段 。
    壞消息, C# 中沒有__leave 語句。但是,在清單 7.5 中的代碼演示了一個你可以實現的方案。

    清單 7.5  從 try語句 跳轉到finally 語句

1: using System;
2:
3: class JumpTest
4: {
5:  public static void Main()
6:  {
7:   try
8:   {
9:    Console.WriteLine("try");
10:    goto __leave;
11:   }
12:   finally
13:   {
14:    Console.WriteLine("finally");
15:   }
16:
17:   __leave:
18:   Console.WriteLine("__leave");
19:  }
20: }


    當這個應用程序運行時,輸出結果為

try
finally
__leave

     一個 goto 語句不能退出 一個finally 語段。甚至把 goto 語句放在 try 語句 段中,還是會立即返回控制到
finally 語段。因此,goto 只是離開了 try 語段并跳轉到finally 語段。直到 finally 中的代碼完成運行后,才能到達
__leave 標簽。按這種方式,你可以模仿在SEH中使用的的__leave 語句。
     順便地,你可能懷疑goto 語句被忽略了,因為它是try 語句中的最后一條語句,并且控制自動地轉移到了
finally 。為了證明不是這樣,試把goto 語句放到Console.WriteLine 方法調用之前。盡管由于不可到達代碼你得到了編
譯器的警告,但是你將看到goto語句實際上被執行了,且沒有為 try 字符串產生的輸出。

7.2.3  使用try-catch-finally處理所有異常
    應用程序最有可能的途徑是合并前面兩種錯誤處理技術——捕獲錯誤、清除并繼續執行應用程序。所有你要做的是在
出錯處理代碼中使用 try 、catch 和 finally語句。清單 7.6 顯示了處理零除錯誤的途徑。

    清單 7.6  實現多個catch 語句

1: using System;
2:
3: class CatchIT
4: {
5:  public static void Main()
6:  {
7:   try
8:   {
9:    int nTheZero = 0;
10:    int nResult = 10 / nTheZero;
11:   }
12:   catch(DivideByZeroException divEx)
13:   {
14:    Console.WriteLine("divide by zero occurred!");
15:   }
16:   catch(Exception Ex)
17:   {
18:    Console.WriteLine("some other exception");
19:   }
20:   finally
21:   {
22:   }
23:  }
24: }

    這個例子的技巧為,它包含了多個catch 語句。第一個捕獲了更可能出現的DivideByZeroException異常,而第二個
catch語句通過捕獲普通異常處理了所有剩下來的異常。
    你肯定總是首先捕獲特定的異常,接著是普通的異常。如果你不按這個順序捕獲異常,會發生什么事呢?清單7.7中的
代碼有說明。

  清單7.7   順序不適當的 catch 語句

1:   try
2:   {
3:    int nTheZero = 0;
4:    int nResult = 10 / nTheZero;
5:   }
6:   catch(Exception Ex)
7:   {
8:    Console.WriteLine("exception " + Ex.ToString());
9:   }
10:   catch(DivideByZeroException divEx)
11:   {
12:    Console.WriteLine("never going to see that");
13:   }


    編譯器將捕獲到一個小錯誤,并類似這樣報告該錯誤:
wrongcatch.cs(10,9): error CS0160: A PRevious catch clause already
catches all exceptions of this or a super type ('System.Exception')

    最后,我必須告發CLR異常與SEH相比時的一個缺點(或差別):沒有 EXCEPTION_CONTINUE_EXECUTION標識符的等價
物,它在SEH異常過濾器中很有用?;旧?,EXCEPTION_CONTINUE_EXECUTION 允許你重新執行負責異常的代碼片段。在重
新執行之前,你有機會更改變量等。我個人特別喜歡的技術為,使用訪問違例異常,按需要實施內存分配。
  

7.3  引發異常
    當你必須捕獲異常時,其他人首先必須首先能夠引發異常。而且,不僅其他人能夠引發,你也可以負責引發。其相當
簡單:

throw new ArgumentException("Argument can't be 5");
    你所需要的是throw 語句和一個適當的異常類。我已經從表7.1提供的清單中選出一個異常給這個例子。
    
    表 7.1   Runtime提供的標準異常


異常類型                                                        描述

Exception                                            所有異常對象的基類
SystemException                                      運行時產生的所有錯誤的基類
IndexOutOfRangeException                             當一個數組的下標超出范圍時運行時引發
NullReferenceException                               當一個空對象被引用時運行時引發
InvalidOperationException                            當對方法的調用對對象的當前狀態無效時,由某些方法引發
ArgumentException                                    所有參數異常的基類
ArgumentNullException                                在參數為空(不允許)的情況下,由方法引發
ArgumentOutOfRangeException                          當參數不在一個給定范圍之內時,由方法引發
InteropException                                     目標在或發生在CLR外面環境中的異常的基類
ComException                                         包含COM 類的HRESULT信息的異常
SEHException                                         封裝win32 結構異常處理信息的異常

    然而,在catch語句的內部,你已經有了隨意處置的異常,就不必創建一個新異常??赡茉诒?.1 中的異常沒有一個符
合你特殊的要求——為什么不創建一個新的異常?在即將要學到小節中,都涉及到這兩個話題。

7.3.1 重新引發異常
    當處于一個catch 語句的內部時,你可能決定引發一個目前正在再度處理的異常,留下進一步的處理給一些外部的
try-catch 語句。該方法的例子如 清單7.8所示。

清單 7.8  重新引發一個異常

1:   try
2:   {
3:    checked
4:    {
5:     for (;nCurDig <= nComputeTo; nCurDig++)
6:      nFactorial *= nCurDig;
7:    }
8:   }
9:   catch (OverflowException oe)
10:   {
11:    Console.WriteLine("Computing {0} caused an overflow exception", nComputeTo);
12:    throw;
13:   }

    注意,我不必規定所聲明的異常變量。盡管它是可選的,但你也可以這樣寫:
    throw oe;
    現在有時還必須留意這個異常。

7.3.2  創建自己的異常類
    盡管建議使用預定義的異常類,但對于實際場合,創建自己的異常類可能會方便。創建自己的異常類,允許你的異常
類的使用者根據該異常類采取不同的手段。
    在清單 7.9 中出現的異常類 MyImportantException遵循兩個規則:第一,它用Exception結束類名。第二,它實現了
所有三個被推薦的通用結構。你也應該遵守這些規則。
    清單  7.9   實現自己的異常類  MyImportantException

1: using System;
2:
3: public class MyImportantException:Exception
4: {
5:  public MyImportantException()
6:   :base() {}
7:
8:  public MyImportantException(string message)
9:   :base(message) {}
10:
11:  public MyImportantException(string message, Exception inner)
12:   :base(message,inner) {}
13: }
14:
15: public class ExceptionTestApp
16: {
17:  public static void TestThrow()
18:  {
19:   throw new MyImportantException("something bad has happened.");
20:  }
21:
22:  public static void Main()
23:  {
24:   try
25:   {
26:    ExceptionTestApp.TestThrow();
27:   }
28:   catch (Exception e)
29:   {
30:    Console.WriteLine(e);
31:   }
32:  }
33: }

    正如你所看到的,MyImportantException 異常類不能實現任何特殊的功能,但它完全基于System.Exception類。程序
的剩余部分測試新的異常類,給System.Exception 類使用一個catch 語句。
    如果沒有特殊的實現而只是給MyImportantException定義了三個構造函數,創建它又有什么意義呢?它是一個重要的
類型——你可以在catch語句中使用它,代替更為普通的異常類。可能引發你的新異常的客戶代碼可以按規定的catch代碼
發揮作用。
    當使用自己的名字空間編寫一個類庫時,也要把異常放到該名字空間。盡管它并沒有出現在這個例子中,你還是應該
使用適當的屬性,為擴展了的錯誤信息擴充你的異常類。

7.4  異常處理的“要”和“不要”
  作為最后的忠告之語,這里是對異常引發和處理所要做和不要做的清單:
。當引發異常時,要提供有意義的文本。
。要引發異常僅當條件是真正異常;也就是當一個正常的返回值不滿足時。
。如果你的方法或屬性被傳遞一個壞參數,要引發一個ArgumentException異常。
。當調用操作不適合對象的當前狀態時,要引發一個 InvalidOperationException異常。
。要引發最適合的異常。
。要使用鏈接異常,它們允許你跟蹤異常樹。
。不要為正?;蝾A期的錯誤使用異常。
。不要為流程的正??刂剖褂卯惓!?br>。不要在方法中引發 NullReferenceException或IndexOutOfRangeException異常。

   7.5  小結
    這一章由介紹溢出校驗開始。你可以使用編譯器開關(默認是關),使整個應用程序允許或禁止溢出校驗。如果需要
微調控制,你可以使用校驗和非校驗語句,它允許你使用或不使用溢出校驗來執行一段代碼,盡管沒有給應用程序設置開
關。
    當發生溢出時,一個異常就被引發了。如何處理異常取決于你。我提出了各種途徑,包括你最有可能貫穿整個應用程
序使用的:try、catch 和finally 語句。在伴隨的多個例子中,你學到了它與WIN32結構異常處理(SEH)的差別。
   異常處理是給類的用戶; 然而,如果你負責創建新的類,就可以引發異常。有多種選擇:引發早已捕獲的異常,引發
存在的框架異常,或者按規定的實際目標創建新的異常類。
   最后,你需要閱讀引發和處理異常的各種“要”和“不要”。



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久亚洲精品不卡| 欧美日韩高清区| 久久综合免费视频影院| 久久人人爽人人爽人人片av高清| 97视频在线观看免费| 91精品久久久久久久久久入口| 中文字幕成人精品久久不卡| 亚洲性无码av在线| 亚洲精品在线不卡| 亚洲精品720p| 一区二区三区视频免费在线观看| 中文字幕无线精品亚洲乱码一区| 成人女保姆的销魂服务| 国产z一区二区三区| 中文字幕在线成人| 欧美日韩精品在线播放| 丰满岳妇乱一区二区三区| 91po在线观看91精品国产性色| 欧美精品videos| 成人97在线观看视频| 中文字幕亚洲一区二区三区五十路| 亚洲高清在线观看| 欧美日韩加勒比精品一区| 亚洲欧美日韩第一区| 欧美精品福利视频| 国外成人性视频| 国产美女主播一区| 色婷婷成人综合| 中文字幕亚洲欧美在线| 成人黄色片在线| 亚洲色图欧美制服丝袜另类第一页| 欧美日韩国产一区中文午夜| 国产成人av网址| 国产精品欧美激情在线播放| 欧美激情第6页| 亚洲成年人在线| 欧美一级视频在线观看| 色偷偷91综合久久噜噜| 亚洲风情亚aⅴ在线发布| 大量国产精品视频| 国产成人精品一区二区| 福利视频第一区| 欧美影院成年免费版| 欧美xxxx18性欧美| 欧美大尺度在线观看| 久久久久一本一区二区青青蜜月| 久久天天躁狠狠躁夜夜躁2014| 91av成人在线| 亚洲成av人影院在线观看| 日韩精品高清在线观看| 最近2019免费中文字幕视频三| 国产精品爽爽爽爽爽爽在线观看| 国产免费一区二区三区在线观看| 日韩欧美在线观看视频| 久久色免费在线视频| 欧美在线观看一区二区三区| 国产精品久久在线观看| 欧美午夜激情小视频| 成人情趣片在线观看免费| 欧美亚洲视频在线看网址| 欧美激情中文网| 亚洲精品99久久久久中文字幕| 欧美福利视频在线观看| 日韩欧美在线视频日韩欧美在线视频| 夜夜嗨av色一区二区不卡| 精品国产91乱高清在线观看| 亚洲美女在线看| 欧美成人在线免费视频| 日本一本a高清免费不卡| 亚洲人成欧美中文字幕| 欧美午夜影院在线视频| 日本久久久久亚洲中字幕| 一区二区在线视频播放| 欧美日韩国产91| 欧美巨乳美女视频| 国产欧美日韩视频| 久久久久久久一| 亚洲男人的天堂在线播放| 国产91成人在在线播放| 国产精品三级在线| 国产精品欧美久久久| 欧美在线一区二区三区四| 自拍偷拍亚洲一区| 欧美大片在线看免费观看| 免费99精品国产自在在线| 日本免费久久高清视频| 91中文在线观看| 欧美伦理91i| 国产亚洲精品91在线| 国产中文欧美精品| 欧美成人一区在线| 91精品久久久久久久久不口人| 影音先锋欧美精品| 欧美美最猛性xxxxxx| 97人人模人人爽人人喊中文字| 久久躁狠狠躁夜夜爽| 国产精品va在线播放我和闺蜜| 色偷偷av亚洲男人的天堂| 欧美日韩国产综合视频在线观看中文| 永久免费毛片在线播放不卡| 神马久久久久久| 欧美日韩福利在线观看| 久久国内精品一国内精品| 国产一级揄自揄精品视频| 欧美国产激情18| 国产成人一区二区三区| 精品一区二区三区四区| 日韩欧美中文字幕在线播放| 精品国产91乱高清在线观看| 日韩欧美aⅴ综合网站发布| 国产69精品99久久久久久宅男| 亚洲精品国产电影| 色婷婷综合成人| 国产精品自拍偷拍| 国产国产精品人在线视| 欧美视频在线视频| 91精品成人久久| 日韩成人在线视频观看| 欧美一区二区三区免费视| 欧美精品久久久久久久| 久久频这里精品99香蕉| 亚洲美女免费精品视频在线观看| 色综合久久精品亚洲国产| 久久久久久97| 国自产精品手机在线观看视频| 亚洲成人三级在线| 精品久久久久久中文字幕一区奶水| 色婷婷综合久久久久| 色综合色综合久久综合频道88| 欧美激情伊人电影| 国产成人精品一区二区三区| 一个人看的www欧美| 国产成人福利网站| 精品国产91久久久久久老师| 欧美在线观看一区二区三区| 91麻豆国产精品| 欧美黄色www| 亚洲男人天堂2023| 九九久久国产精品| 国产欧美精品在线播放| 欧美美女18p| 国产日韩中文在线| 国产精品久久久久久久7电影| 成人一区二区电影| 欧美激情精品久久久久久| 91香蕉国产在线观看| 亚洲精品白浆高清久久久久久| 91亚洲国产成人精品性色| 在线日韩精品视频| 欧美性xxxxhd| 中文字幕9999| 亚洲精品女av网站| 亚洲国产古装精品网站| 亚洲综合中文字幕在线| 亚洲国产精品女人久久久| 色偷偷偷综合中文字幕;dd| 91国语精品自产拍在线观看性色| 日韩有码片在线观看| 琪琪亚洲精品午夜在线| 在线一区二区日韩| 亚洲人成在线一二| 日韩中文字幕在线视频| 国产精品成人国产乱一区| 日韩精品久久久久久久玫瑰园|