深夜裡的守衛進階篇
夜又深了一點。城市沉睡,資料仍在流動。守衛們站在崗位上,他們已經不再只是「接住錯誤」,而是要學會 如何命名、如何回報、如何協同。這是守衛的進階修煉。
🪪 守衛的身份 —— Custom Exception
在黑夜裡,錯誤四處遊走。如果每位守衛都只高喊「發生了錯誤!」,那麼城裡的人永遠無法分辨:到底是火災、盜賊,還是野獸入侵?這就是 Custom Exception 的意義。
1 | public class PayException : Exception |
與其到處貼上 HappyPayException、CoolPayException,有時不如直接說:「這是付款業務的錯誤」。
這增強了系統金流錯誤處理的通用性,不論金流服務換誰,守衛喊的口號都一樣。在夜晚,有時守衛最重要的不是鉅細靡遺交代細節,而是讓人快速判斷問題的範圍。
📜 巡邏的回報 —— throw vs throw ex
「是我發現的錯誤!」(throw ex)
「錯誤在那邊,是它自己!」(throw)
1 | void Main() |
- throw ex
會建立一個「新的例外拋出點」。原始的呼叫堆疊(stack trace)會被覆蓋,錯誤看起來就像只發生在 ThrowEx(),而看不到 ExceptionMaker()。這會導致除錯困難,因為錯誤源頭被「隱藏」了。
- throw
重新拋出「原本捕捉到的例外」。會完整保留原始的 stack trace。因此可以追蹤到錯誤最初發生的位置 (ExceptionMaker()),這才是 最佳實踐。
🛠 守衛的新工具 —— throw Expression
時代在進步,守衛也有了更靈活的工具。在 C# 7 之後,throw 不再只能是一句話,而能融入表達式(會產生一個「值」的程式片段),像短劍般隨時可用。
1 | // Ternary Operator |
過去需要一大段判斷,如今一句話即可表達。守衛的效率提高了,也讓城市裡的規則更簡潔。
⚔️ 突發的多點騷動 —— 並行例外
夜裡的城牆並非只有一個入口。有時,敵人會同時從不同方向發動攻擊。這就是 並行錯誤。在傳統的 Thread 世界裡,守衛只能各自為戰:
1 | new Thread(() => |
但在 Task 的世界裡,錯誤會被集中起來,像是守城總管收到所有守衛的戰報:
1 | try |
但 await Task.WhenAll(…) 不會丟 AggregateException,它會「拆封」(unwrap) 成 第一個例外直接拋出。如果想捕捉多個例外,光用 catch (AggregateException) 是抓不到的(因為它被 await 拆掉了)。
正確的寫法是 catch (Exception ex),再回頭去巡覽 tasks 的 Exception。
1 | try |
📋 檢查清單 —— TryParse
有些錯誤,不是敵人入侵,而是日常的小意外。例如資料格式不符,就像有人在名冊上寫錯了字。
這時候,守衛不需要敲鑼打鼓,只要輕輕記下來就好。
- 使用 Parse → 你假設「資料一定正確」,只要失敗就是「重大異常」。
- 使用 TryParse → 你承認「資料輸入可能會錯」,而這是「日常的一部分」。
當「輸入不可信」時(例如使用者輸入、外部檔案、第三方資料來源),TryParse 就是更貼近本質的選擇。使用 TryXxx API,表示我們認為這是正常流程的一部份,就像我們生活上遇到大大小小的鳥事,我們如果都秉持著 TryParse 的態度,生活才能正常前進吧
程式案例 : 讀檔進來並且一行行解析內容
1 | var errors = new List<string>(); |
這個案例來說,出錯是常態,但不該打擾整個流程。只需在 log 上留下記錄,等白天再交給人去處理。
這也提醒我們:不是每個錯誤都要當作警報,有些只是小小的不符合,需要被妥善分類。
📂 開檔
說道開檔,我們可能會想先 File.Exists,再 File.Open。但僅僅如此並不保證安全因為
- 檔案在你檢查時存在,但在你打開前就被刪了。
- 檔案在你檢查時不存在,但你要開時剛好又被建立了。
- 所以「檔案開啟」這類操作本質上就是「要嘛成功,要嘛例外」,無法完全靠 Try 來解決。
所以他沒有 TryOpen,因為檔案存在與否不是常態錯誤,而是環境不可控的異常,唯一正確做法就是 Open + catch,catch 再 rethrow,如我我們可以
- 紀錄錯誤(Log)
- 補充業務語境(轉成自訂 Exception)
- 做一些補救措施後,再把錯誤往上拋
其他類似情境
- 檔案不存在 → FileNotFoundException。
- 硬碟 IO 出錯 → IOException。
- 權限不足 → UnauthorizedAccessException。
程式案例
1 | try |
1 | try |
🌃 結語
夜色漸漸散去,第一道曙光爬上城牆。守衛們收起火把,留下巡邏時的紀錄、錯誤的線索與訊息。
他們沒有阻止黑夜的到來,也不可能讓城市永遠不出差錯。
他們的價值,在於
當錯誤真的發生時,能清楚喊出「是哪一類敵人」——就像 Custom Exception。
當需要回報時,不會隱藏真相,而是如實呈現來源——就像 throw 而不是 throw ex。
面對日常的細碎錯誤,懂得輕描淡寫,不讓城市陷入慌亂——就像 TryParse 的哲學。
而當環境失常、檔案無法開啟,他們選擇留下紀錄,補上語境,將訊息交給下一位接班者。
錯誤處理的本質,不在於避免黑夜,而是在黑夜裡守護秩序。程式的世界亦然:我們不可能消滅所有錯誤,但我們可以設計一套守衛的機制,讓錯誤不會成為災難,而是成為訊息,讓白日裡的工程師能夠快速回應。