• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    <展現C#> 第七章 異常處理(rainbow 翻譯)

    發布: 2007-6-30 18:56 | 作者: admin | 來源: | 查看: 11次 | 進入軟件測試論壇討論

    領測軟件測試網 第七章 異常處理

    通用語言運行時(CLR)具有的一個很大的優勢為,異常處理是跨語言被標準化的。一個在C#中所引發的異?梢栽
    Visual 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語句的內部,你已經有了隨意處置的異常,就不必創建一個新異常?赡茉诒7.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語句中使用它,代替更為普通的異常類?赡芤l你的新異常的客戶代碼可以按規定的catch代碼
    發揮作用。
    當使用自己的名字空間編寫一個類庫時,也要把異常放到該名字空間。盡管它并沒有出現在這個例子中,你還是應該
    使用適當的屬性,為擴展了的錯誤信息擴充你的異常類。

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

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

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>