
程式在執行的時候可能會發生例外的問題。當遇到這些不在意料之中的問題,而在開發程式的時候又沒有對例外 (exception)進行任何的處理,就會導致程式直接停止運行,進而使正在進行的資料處理無法正確完成,例如資料庫的 CRUD 操作,或是將錯誤內容呈現給使用者,這樣會造成不好的用戶體驗。此外如果不幸資料外洩,也會增加遭受有心人士攻擊的風險。
為了避免這些問題的發生,C# 提供了針對例外狀況的處理方式。本文將分享最基本的使用方法。
那例外 (Exception)是什麼呢?在不同系統或程式語言中,各有自己的解釋。在 C# 開發程式裡,例外指的是應用程式在執行中發生的錯誤。造成錯誤的原因有很多,可能是使用者輸入的內容有誤,或是開發的程式碼裡有錯誤的程式邏輯。在 C# 中,可以透過一些關鍵字來處理這些錯誤,關鍵字如下:try、catch、finally。

try:主要的程式碼區塊,當執行此區塊時發生例外,剩下的程式碼將不會再執行。
catch:當 try 區塊發生例外時,會跳進來執行的程式碼。catch 可以有多個,用於針對不同的例外類型進行不同的處理。
finally:在程式沒有直接停止運行的情況下,無論有無發生例外,這段程式碼都會被執行。通常用來釋放資源,例如關閉資料庫的連接。
接下來,沿用部落格的一篇文章「使用 CsvHelper 讀取 CSV 檔案」中的範例,來實作try-catch-finally。
首先是 try-catch 的部分,當上傳一份檔案格式不符合的檔案時,將會發生錯誤,如下圖所示:

▸上傳檔案格式不符合的檔案

▸產生錯誤
因為程式設定讀取的檔案需要包含標頭,因此上傳不包含標頭的檔案會導致程式錯誤並直接停止運行。所以加上 try-catch 來處理例外狀況。

▸加上try-catch之後的程式碼
接下來解釋加上try-catch後的各段落程式碼負責的部分:
try區塊:負責讀取 CSV 並將取得的資料添加到列表中,詳細的做法可以參考「使用 CsvHelper 讀取 CSV 檔案」。
catch區塊:負責處理例外,從程式碼中可以看到這裡寫了兩個catch區塊,分別處理不同的例外:
▸ catch (CsvHelperException ex):這個區塊用來處理 CsvHelper 的例外,例如檔案格式錯誤、缺少標頭等問題。此外,程式碼中還有一行,當捕捉到這個例外時,會回傳一個 Alert 告訴用戶「CSV 讀取錯誤」。
▸ catch (Exception ex):這個區塊用來處理沒有被特別指定的例外錯誤,同樣也有一行,當捕捉到例外時,會回傳一個 Alert 告訴用戶「讀取錯誤」。

▸重新執行程式碼後,再上傳不包含表頭的檔案,可以看到頁面跳出顯示「CSV 讀取錯誤」的 Alert
接下來,在 finally 的區塊將順便示範如何產生 Log。finally 區塊只要程式沒有被停止,就會執行。而 Log 對於開發者來說,是一個可以追蹤程式執行狀況的工具,並且可以記錄錯誤訊息。因此,在 finally 區塊產生 Log 可以有效幫助開發者找到問題並進行修正。
首先,寫一個函式,主要傳入 fileName、message、jsonException,分別的用意如下:
fileName:當前處理的檔案名稱。
message:要記錄的主要信息。
jsonException:如果有異常發生,將其以 JSON 格式記錄,用於提供錯誤的具體信息。
接下來,設定 Log 文件要建立的資料夾位置以及檔案名稱的格式。在確定目錄存在後,就可以開始寫入 Log 的內容,包含時間、傳入的 message 和 jsonException。最後,加上分隔線以區隔不同的 Log 內容,這樣就簡略地完成了 Log 的function如下圖所示:

▸Log的function
接下來在想要紀錄的地方呼叫Log function 如下圖所示:

▸呼叫Log function
這樣在執行程式時,就會寫入 Log 內容以記錄追蹤程式執行的狀況或查看錯誤資訊。

▸寫入的檔案

▸寫入的內容
結語
因為在開發時可能會有很多例外發生,但在寫文章做筆記的同時,了解 C# 中有try-catch-finally可以初步簡單地處理這些例外。此外,也可以透過 Log 紀錄來了解程式執行的狀況並快速找到問題。這不僅可以提高程式的品質,也能讓用戶有更好的使用體驗。在文章中提供的範例只是非常簡單的程度,如果需要更多資訊或資料,可以參考下方的連結,前往閱讀並找到更多範例。
參考:
Exception 類別
例外狀況和例外狀況處理
C# 例外處理(Exception Handling)
例外狀況處理陳述式 – throw、try-catch、try-finally 和try-catch-finally
[C#] Exception的基本使用方法 try catch finally
C#try-catch-finally的finally的作用是什麼?