在這里,您將學(xué)習(xí)使用try,catch和finally塊在C#中進(jìn)行異常處理的知識(shí)。
必須處理應(yīng)用程序中的異常,以防止程序崩潰和意外結(jié)果,記錄異常并繼續(xù)執(zhí)行其他功能。C#提供內(nèi)置支持使用 try,catch和finally塊 來(lái)處理異常。
語(yǔ)法:
try
{
// 將代碼放在這里可能會(huì)引發(fā)異常
}
catch
{
// 在這里處理異常
}
finally
{
// 最終清理代碼
}try 塊:任何可能引發(fā)異常的可疑代碼都應(yīng)放在一個(gè)try{ }塊中。在執(zhí)行過(guò)程中,如果發(fā)生異常,則控制流跳至第一個(gè)匹配catch塊。
catch 塊:catch塊是異常處理程序塊,您可以在其中執(zhí)行一些操作,例如記錄和審核異常。catch塊采用異常類型的參數(shù),您可以使用該參數(shù)獲取異常的詳細(xì)信息。
finally 塊:finally無(wú)論是否引發(fā)異常,都將始終執(zhí)行該塊。通常,finally應(yīng)該使用一個(gè)塊來(lái)釋放資源,例如,關(guān)閉在try塊中打開的任何流或文件對(duì)象。
如果您輸入非數(shù)字字符,則以下內(nèi)容可能會(huì)引發(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}");
}
}要在上面的示例中處理可能的異常,請(qǐng)將代碼包裝在一個(gè)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.");
}
}
}在上面的示例中,我們將此代碼包裝在一個(gè)try塊中。如果try塊內(nèi)發(fā)生異常,則程序?qū)⑻D(zhuǎn)到該catch塊。在catch塊內(nèi),我們將顯示一條消息以指示用戶有關(guān)其錯(cuò)誤的信息,在finally塊內(nèi),我們將顯示一條有關(guān)運(yùn)行程序后的操作的消息。
try塊必須跟catch或finally或兩種嵌段。在try不使用塊catch或finally塊將給出一個(gè)編譯時(shí)錯(cuò)誤。
理想情況下,catch塊應(yīng)包含內(nèi)置或自定義異常類的參數(shù)以獲取錯(cuò)誤詳細(xì)信息。以下包括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ù)的多個(gè)塊。這稱為異常過(guò)濾器。當(dāng)您想以不同的方式處理不同類型的異常時(shí),異常過(guò)濾器很有用。
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("不能被零除。請(qǐng)?jiān)僭囈淮?");
}
catch(InvalidOperationException ex)
{
Console.Write("無(wú)效操作。請(qǐng)?jiān)僭囈淮?");
}
catch(FormatException ex)
{
Console.Write("不是有效格式。 請(qǐng)?jiān)僭囈淮?");
}
catch(Exception ex)
{
Console.Write("發(fā)生錯(cuò)誤!請(qǐng)?jiān)僭囈淮?");
}
}
}在上面的示例中,我們指定了catch具有不同異常類型的多個(gè)塊。我們可以根據(jù)錯(cuò)誤向用戶顯示適當(dāng)?shù)南?,因此用戶不?huì)再次重復(fù)相同的錯(cuò)誤。
在同一 try..catch語(yǔ)句中不允許使用無(wú)參數(shù)catch塊和帶有Exception參數(shù)的catch塊,因?yàn)樗鼈兌紙?zhí)行相同的操作。
try
{
//可能引發(fā)異常的代碼
}
catch //不能同時(shí)具有catch和catch(Exception 異常)
{
Console.WriteLine("Exception occurred");
}
catch(Exception ex) //不能同時(shí)具有catch和catch(異常異常)
{
Console.WriteLine("Exception occurred");
}另外,無(wú)參數(shù) catch 塊 catch {}或通用 catch 塊 catch (Exception ex){}必須是最后一個(gè)塊。如果在 catch {}或 catch (Exception ex)塊之后還有其他 catch 塊,編譯器將給出錯(cuò)誤。
示例:無(wú)效的catch 捕獲
try
{
//可能引發(fā)異常的代碼
}
catch
{
// 該捕獲塊必須是最后一個(gè)塊
}
catch (NullReferenceException nullEx)
{
Console.WriteLine(nullEx.Message);
}
catch (InvalidCastException inEx)
{
Console.WriteLine(inEx.Message);
}finally塊是可選塊,應(yīng)在try或catch塊之后。無(wú)論是否發(fā)生異常,都將始終執(zhí)行 finally 塊。finally塊通常用于清理代碼,例如處理非托管對(duì)象。
示例: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
{
// 在這里清理文件對(duì)象;
file = null;
}
}finally不允許使用 多個(gè)塊。另外,finally塊不能包含return,continue或break關(guān)鍵字。它不允許控制權(quán)離開finally塊。
C#允許嵌套try-catch塊。當(dāng)使用嵌套的try-catch塊時(shí),將在發(fā)生異常catch的try塊之后的第一個(gè)匹配塊中捕獲異常。
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í)行一個(gè)內(nèi)部塊,因?yàn)樗莄atch處理所有異常類型的第一個(gè)塊。
如果沒(méi)有與拋出的異常類型匹配的內(nèi)部catch塊,則控制將流向外部catch塊,直到找到合適的異常篩選器??聪旅娴膶?shí)例。
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塊處理。