在這里,您將學(xué)習(xí)使用try,catch和finally塊在C#中進行異常處理的知識。
必須處理應(yīng)用程序中的異常,以防止程序崩潰和意外結(jié)果,記錄異常并繼續(xù)執(zhí)行其他功能。C#提供內(nèi)置支持使用 try,catch和finally塊 來處理異常。
語法:
try { // 將代碼放在這里可能會引發(fā)異常 } catch { // 在這里處理異常 } finally { // 最終清理代碼 }
try 塊:任何可能引發(fā)異常的可疑代碼都應(yīng)放在一個try{ }塊中。在執(zhí)行過程中,如果發(fā)生異常,則控制流跳至第一個匹配catch塊。
catch 塊:catch塊是異常處理程序塊,您可以在其中執(zhí)行一些操作,例如記錄和審核異常。catch塊采用異常類型的參數(shù),您可以使用該參數(shù)獲取異常的詳細信息。
finally 塊:finally無論是否引發(fā)異常,都將始終執(zhí)行該塊。通常,finally應(yīng)該使用一個塊來釋放資源,例如,關(guān)閉在try塊中打開的任何流或文件對象。
如果您輸入非數(shù)字字符,則以下內(nèi)容可能會引發(fā)異常。
class Program { static void Main(string[] args) { Console.WriteLine("Enter a number: "); var num = int.Parse(Console.ReadLine()); Console.WriteLine($"Squre of {num} is {num * num}"); } }
要在上面的示例中處理可能的異常,請將代碼包裝在一個try塊中,然后在catch塊中處理異常,如下所示。
class Program { static void Main(string[] args) { try { Console.WriteLine("Enter a number: "); var num = int.parse(Console.ReadLine()); Console.WriteLine($"Squre of {num} is {num * num}"); } catch { Console.Write("Error occurred."); } finally { Console.Write("Re-try with a different number."); } } }
在上面的示例中,我們將此代碼包裝在一個try塊中。如果try塊內(nèi)發(fā)生異常,則程序?qū)⑻D(zhuǎn)到該catch塊。在catch塊內(nèi),我們將顯示一條消息以指示用戶有關(guān)其錯誤的信息,在finally塊內(nèi),我們將顯示一條有關(guān)運行程序后的操作的消息。
try塊必須跟catch或finally或兩種嵌段。在try不使用塊catch或finally塊將給出一個編譯時錯誤。
理想情況下,catch塊應(yīng)包含內(nèi)置或自定義異常類的參數(shù)以獲取錯誤詳細信息。以下包括Exception捕獲所有類型的異常的type參數(shù)。
class Program { static void Main(string[] args) { try { Console.WriteLine("Enter a number: "); var num = int.parse(Console.ReadLine()); Console.WriteLine($"Squre of {num} is {num * num}"); } catch(Exception ex) { Console.Write("Error info:" + ex.Message); } finally { Console.Write("Re-try with a different number."); } } }
您可以使用catch具有不同異常類型參數(shù)的多個塊。這稱為異常過濾器。當您想以不同的方式處理不同類型的異常時,異常過濾器很有用。
class Program { static void Main(string[] args) { Console.Write("Please enter a number to divide 100: "); try { int num = int.Parse(Console.ReadLine()); int result = 100 / num; Console.WriteLine("100 / {0} = {1}", num, result); } catch(DivideByZeroException ex) { Console.Write("不能被零除。請再試一次."); } catch(InvalidOperationException ex) { Console.Write("無效操作。請再試一次."); } catch(FormatException ex) { Console.Write("不是有效格式。 請再試一次."); } catch(Exception ex) { Console.Write("發(fā)生錯誤!請再試一次."); } } }
在上面的示例中,我們指定了catch具有不同異常類型的多個塊。我們可以根據(jù)錯誤向用戶顯示適當?shù)南ⅲ虼擞脩舨粫俅沃貜?fù)相同的錯誤。
在同一 try..catch語句中不允許使用無參數(shù)catch塊和帶有Exception參數(shù)的catch塊,因為它們都執(zhí)行相同的操作。
try { //可能引發(fā)異常的代碼 } catch //不能同時具有catch和catch(Exception 異常) { Console.WriteLine("Exception occurred"); } catch(Exception ex) //不能同時具有catch和catch(異常異常) { Console.WriteLine("Exception occurred"); }
另外,無參數(shù) catch 塊 catch {}或通用 catch 塊 catch (Exception ex){}必須是最后一個塊。如果在 catch {}或 catch (Exception ex)塊之后還有其他 catch 塊,編譯器將給出錯誤。
示例:無效的catch 捕獲
try { //可能引發(fā)異常的代碼 } catch { // 該捕獲塊必須是最后一個塊 } catch (NullReferenceException nullEx) { Console.WriteLine(nullEx.Message); } catch (InvalidCastException inEx) { Console.WriteLine(inEx.Message); }
finally塊是可選塊,應(yīng)在try或catch塊之后。無論是否發(fā)生異常,都將始終執(zhí)行 finally 塊。finally塊通常用于清理代碼,例如處理非托管對象。
示例:finally塊
static void Main(string[] args) { FileInfo file = null; try { Console.Write("Enter a file name to write: "); string fileName = Console.ReadLine(); file = new FileInfo(fileName); file.AppendText("Hello World!") } catch(Exception ex) { Console.WriteLine("Error occurred: {0}", ex.Message ); } finally { // 在這里清理文件對象; file = null; } }
finally不允許使用 多個塊。另外,finally塊不能包含return,continue或break關(guān)鍵字。它不允許控制權(quán)離開finally塊。
C#允許嵌套try-catch塊。當使用嵌套的try-catch塊時,將在發(fā)生異常catch的try塊之后的第一個匹配塊中捕獲異常。
static void Main(string[] args) { var divider = 0; try { try { var result = 100/divider; } catch { Console.WriteLine("Inner catch"); } } catch { Console.WriteLine("Outer catch"); } }
Inner catch
catch在上面的示例中,將執(zhí)行一個內(nèi)部塊,因為它是catch處理所有異常類型的第一個塊。
如果沒有與拋出的異常類型匹配的內(nèi)部catch塊,則控制將流向外部catch塊,直到找到合適的異常篩選器??聪旅娴膶嵗?br/>
static void Main(string[] args) { var divider = 0; try { try { var result = 100/divider; } catch(NullReferenceException ex) { Console.WriteLine("Inner catch"); } } catch { Console.WriteLine("Outer catch"); } }
Outer catch
在上面的示例中,將引發(fā)類型異常 DivideByZeroException 。由于內(nèi)部catch塊僅處理NullReferenceTypeException,因此將由外部catch塊處理。