前言

寫程式的各位,一定常常會遇到需要用到try & catch 的時候。

try & catch 的作用是什麼?

簡單來說就歸納出兩個使用契機

可以避免程式在執行時碰到不可逾期的錯誤

可以在「已預期的結果」的情境中,針對符合條件的部分,去做例外處理

絕大部分我們做try & catch 時,都是避免程式發生崩潰(crash)造成無法運行。

所以,只要程式不發生crash,

那麼基本上,程式都還是有辦法運作的。(功能正不正常就是另一回事了)

1
2
3
4
5
6
7
8
9
//程式發生例外錯誤的簡單範例
static void Main(string[] args)
{
string a = null;
a = a.ToString();

Console.WriteLine(a);
Console.ReadKey();
}

上述範例就是一個很簡單的程式崩潰例子。

假如把null值去做.ToString() 的字串處理的話,

程式就會Crash給你看了。(命令視窗會直接關掉不見)

在程式碼越多越複雜的情況下,大家都不能保證都不會出現所謂的例外錯誤

所以,通常我們會將部分程式碼用try & catch 給包起來,

來避免例外錯誤情形的發生導致程式crash.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//包try & catch的簡單範例
try
{
string a = null;
a = a.ToString();

Console.WriteLine(a);
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();

同樣的程式碼,當給try & catch 包起來執行後,

就不會跳出崩潰錯誤,我們則可以順利執行至命令視窗上了。

當我們寫的程式碼在try{…}區域出現例外狀況時,

catch(){…}執行區段就能夠捕捉到例外,

並且可以定義當發生例外狀況時,我們該做什麼處理

try & catch 的規則及一些用法

一句完整的try…catch中,try的區域僅能一個、catch則可以有數個

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
try
{
//主程式碼內容
//...
//...
}
catch(myException myex) {
{
//接到例外狀況時執行的程式碼-1
//...
}
catch(Exception ex)
{
//接到例外狀況時執行的程式碼-2
//...
}
//不論做完try或是catch後,最後一定會執行到的程式碼
finally
{
//...
}

我們可以定義catch中要做哪種例外類型的捕捉:

異常類型 功能
System.IO.IOException 捕捉I/O的錯誤。
System.IndexOutOfRangeException 處理超出索引範圍所發生的錯誤。
System.ArrayTypeMismatchException 處理數組類型不匹配所發生的錯誤。
System.NullReferenceException 處理對null空對象所發生的錯誤。
System.DivideByZeroException 處理對除以0所發生的錯誤。
System.InvalidCastException 處理在轉換類型時所發生的錯誤。
System.OutOfMemoryException 處理內存不足時所發生的錯誤。
System.StackOverflowException 處理擲回執行堆疊溢位錯誤。

以上是幾個常用異常捕捉的類型,有些人會選擇省略括號()catch{…}這樣寫,

當然也可以自定義例外,來為自己寫的程式做更準確、且符合自己期待的處理內容。

1
2
3
4
5
6
7
//記得要繼承Exception類型 才能在catch中使用
public class myException: Exception
{
//...
//...
//...
}

以上對於try & catch 的用法大家應該也不陌生了。

至於finally{…}的用法(不管做完try還是catch,最後一定會做到的程式內容),就不多做贅述了。

這邊除了幫自己複習一下,也順道可以讓程式新人在寫程式時,

更清楚的知道當碰到例外狀況時,需要做哪些處理。

複習考題

既然大家都明白了實際try & catch 的用法了,那我們來測驗一下下面的考題吧。

問題1. 請問輸出的[c]打至命令字元上的答案是多少?

A: 3
B: 12
C: 123
D: 6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Program.cs
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(tt.QnA());
}
}
//tt.QnA
public static string QnA()
{
string c = "";
try
{
Employee emp = null;
c += "1";
emp.getEmp();
}
catch (Exception ex)
{
c += "2";
return c;
}
finally
{
c += "3";
}
return c;
}

答案:B

假如第一次就答對的人,那麼你肯定是一位非常細膩的人

但如果是回答AD的…先去看清楚c是什麼型別啦!

解答

其實這題有點小陷阱。

這題字串c,因為finally內的程式是不管如何都會被執行到

所以c的值最終會是「123」沒錯,

但是,在catch(){…}中我們已經先return c了,

因此,雖然字串c的最終結果會是「123」,但是打在命令視窗的結果則是「12」了。

你答對了嗎~

覺得答錯不甘心想再嘗試看看嗎?沒問題~那我再出一題!

問題2. 請問[c]的值是多少?

題目這次可要看清楚唷

A: 1245
B: 12345
C: 134
D: 1234

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Program.cs
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(tt.QnA2());
}
}
//tt.QnA2
public static string QnA2()
{
string c = "";
try
{
Employee emp = null;
c += "1";
emp.getEmp();
}
catch (NullReferenceException ex)
{
c += "2";
}
catch(Exception ex2)
{
c += "3";
return c;
}
finally
{
c += "4";
}
c+= "5";
return c;
}

答案:A

這次你有答對了嗎?

為什麼會是A呢?因為:

–程式中若已捕捉例外進入catch(){…}後,則後面所有的catch(){…}都會被忽略掉–

所以題目裡,程式只會進入到第一個catch(NullReferenceException ex){…}裡面而已

後面第二個catch(Exception ex){…}則會被跳過不執行

接下來…既然途中都沒碰到return了… 那自然而然程式就會執行到最後結束了。

所以最終答案就是:

不論字串c或者是命令視窗上面,結果都會是1245

結語

  • 當認為程式有不可知的錯誤發生可能時,可以利用try & catch 來防止程式崩潰。
  • 在完整的try & catch 中,try只能有一個,catch則可以有很多個,但要記得,當進入第一個catch(){…}後,其他的catch(){…}行為都會略過不會進入。
  • finally{…}是不管try{…}catch(){…}後,都會被執行的區段,但是要注意假如程式進finally{…}前有遇到retuen或是throw等處理方式時,回傳值的部份要更多加留意。

以上淺談,希望能對你會有所幫助