天天看點

ASP.NET開發 筆試題目詳解(5)——override與overload,DataReader和DataSet,C#的異常處理機制

問題十一:  override與overload的差別。

override(重寫)修飾符,覆寫一個基類中的方法。

overload(重載)則是将同名方法重新寫過,達到同名的函數實作不同的功能。進而實作了一個方法有不同的版本。

問題十二:  DataReader和DataSet的異同。

DataReader和DataSet最大的差別在于,DataReader使用時始終占用SqlConnection,線上操作資料庫。任何對SqlConnection的操作都會引發DataReader的異常。因為DataReader每次隻在記憶體中加載一條資料,是以占用的記憶體是很小的。因為DataReader的特殊性和高性能,是以DataReader是隻進的,你讀了第一條後就不能再去讀取第一條了。

DataSet則是将資料一次性加載在記憶體中,抛棄資料庫連接配接,是離線操作資料庫。讀取完畢即放棄資料庫連接配接。因為DataSet将資料全部加載在記憶體中,是以比較消耗記憶體,但是确比DataReader要靈活,可以動态的添加行、列、資料,對資料庫進行回傳更新操作。

問題十三:  C#的異常處理機制。

Try...Catch...Finally 異常處理程式的 Try 塊包含希望錯誤處理程式監視的代碼節。如果該代碼節中的任何代碼在執行期間發生錯誤, 将檢查 Try...Catch...Finally 内的每個 Catch 語句,直到找到條件與該錯誤比對的語句。如果找到了這樣的語句,則控制轉移到 Catch 塊内的第一個代碼行。如果沒有找到比對的 Catch 語句,則繼續搜尋包含發生異常的塊的外部 Try...Catch...Finally 塊的 Catch 語句。此過程在整個堆棧中繼續,直到在目前過程中找到比對的 Catch 塊。如果沒有找到,将産生錯誤。

Finally 節中的代碼總是最後執行,并且剛好在錯誤處理塊失去範圍之前執行,不論 Catch 塊内的代碼是否已執行。将清理代碼(如用于關閉檔案和釋放對象的代碼)放在 Finally 節中。

詳細解釋如下:

(1)Throw

在發生引發異常的條件時,可以用 throw 語句來對發出信号。例如,如果例程要求非空字元串作為參數,則它可能包含下列代碼:

public void Process(string location){
   if (location == null)
   throw new ArgumentNullException("null value", "location");
}
           

在該示例中,ArgumentNullException 的新執行個體是用特定的消息和參數名稱來建立的,throw 語句用于引發它。

(2)Try-Catch

用于編寫錯誤處理的最基本的構造是 try-catch。考慮下列代碼:

   try{
      Process(currentLocation);
      Console.WriteLine("Done processing");
   }
   catch (ArgumentNullException e)
   {
      // handle the exception here
   }
           

在該示例中,如果 ArgumentNullException 被 try 塊中的代碼引發(在此情況下,是 Process() 函數),控制将被立即轉到 catch 塊,而不會執行 Console.WriteLine() 調用。

(3)更通用的捕捉:

在上一個示例中,catch 子句捕捉到了 ArgumentNullException,它完全與 Process() 所引發的異常比對。

不過,這不是一項要求。Catch 子句将捕捉指定的異常或者任何從該類派生的異常。例如:

   try
   {
      Process(currentLocation);
      Console.WriteLine("Done processing");
   }
   catch (ArgumentException e)
   {
      // handle the exception here
   }
           

由于 ArgumentNullException 是從 ArgumentException 派生的,是以該 catch 子句将捕捉任何一種異常。此外,它還将捕捉其他的派生異常:ArgumentOutOfRangeException、InvalidEnumArgumentException 和 DuplicateWaitObjectException。

由于所有的異常歸根到底都是從 Exception 類派生的,是以捕捉 Exception 将捕捉任何異常。對了,不是捕捉任何異常;這是因為 C++ 不會将使用者限制為隻引發從 Exception 派生的類,C# 提供了捕捉所有異常的文法:

   catch
   {
      // handle the exception here
   }
           

盡管這個文法是為了完整性而提供的,但是實際上很少使用它。大部分的 C++ 程式都将選擇引發從 Exception 派生的異常,并且即使它們不這樣做,此 catch 文法也不會讓您超出引發了什麼。

(4)Catch 排序:

對于給定的 try 子句,可以有一個以上的 catch 子句,每個 catch 捕捉不同的異常類型。在上一個示例中,對 ArgumentException 進行特殊處理,然後對所有其他異常進行别的處理可能很合适。選擇最具體的(即,派生程度最大的)catch 子句。

那麼示例将是這樣的:

   try
   {
      Process(currentLocation);
      Console.WriteLine("Done processing");
   }
   catch (ArgumentException e)
   {
      // handle the exception here
   }
   catch (Exception e)
   {
      // handle the more general exception here
   }
           

當使用多個 catch 子句時,導出類型必須始終列在任何基類型之前(或者,以從比較合适到不太合适的順序列出)。這是為了提高可讀性。通過閱讀較早的 catch 子句,您可以确定運作時行為将是什麼。

(5)Catch 操作::

既然我們已經捕捉到了異常,我們可能希望對它來做一些有意義的事情。我們可能想做的第一件事是用一些附加的上下文資訊包裝異常。

這是以下面的方式來實作的:

   try
   {
      Process(currentLocation);
      Console.WriteLine("Done processing");
   }
   catch (ArgumentException e)
   {
      throw new ArgumentException("Error while processing", e);
   }
           

它為 ArgumentException 使用擷取一個消息和另一個異常的構造函數。該構造函數将把傳遞的異常包裝在新的異常中,而那個新的将被引發。

此過程為開發人員帶來了巨大的好處。不是隻獲得單個一條有關所發生的事情的資訊,包裝異常還提供了一種類似堆棧跟蹤的東西:

Exception occurred:

System.Exception: Exception in Test1

---> System.Exception: Exception in Test2

---> System.DivideByZeroException: Attempted to divide by zero.
           

這樣的輸出使調試變得容易得多。如果用 /debug 編譯,在各個等級上還将獲得檔案名和行号。

包裝有助于為調試提供附加的資訊。另一種方案是針對需要根據異常采取一些操作的情況。将輸出發送到檔案的代碼看起來可能是這樣的:

   try
   {
        FileStream f = new FileStream(filename, FileMode.Create);
        StreamWriter s = new StreamWriter(f);
        s.WriteLine("{0} {1}", "test", 55);
        s.Close();
        f.Close();     
   }
   catch (IOException e)
   {
      Console.WriteLine("Error opening file {0}", filename);
      Console.WriteLine(e);
   }
           

如果檔案不能打開,則引發異常,激發 catch,出現錯誤,而程式可以繼續執行。在許多情況下,這沒問題。

不過,在這種情況下就存在問題。如果異常在檔案打開之後發生,則檔案将無法關閉。這很糟糕。

所需要的是確定即使發生了異常也可以關閉檔案的方法。

(6)Try-Finally

finally 構造用于指定即使發生異常也始終會運作的代碼。finally 通常用于清理發生異常時所産生的内容。修訂上一個示例:

   try
   {
        FileStream f = new FileStream(filename, FileMode.Create);
        StreamWriter s = new StreamWriter(f);
        s.WriteLine("{0} {1}", "test", 55);
        s.Close();
        f.Close();     
   }
   catch (IOException e)
   {
      Console.WriteLine("Error opening file {0}", filename);
      Console.WriteLine(e);
   }
   finally
   {
      if (f != null)
         f.Close();
   }
           

使用修訂後的代碼,即使發生了異常 finally 子句也将被運作。

繼續閱讀