關於本書
本書目前為Beta 版,預計出版日期為 2026 年 11 月。
在正式出版之前,全書內容、章節架構與範例程式碼仍處於持續編修階段,內容可能隨時更新。若您在閱讀過程中發現任何錯漏或有改進建議,歡迎提出回饋,協助讓本書更加完善。
本書介紹如何在 C# 中運用不可變資料設計(immutable data design),降低可變狀態在程式中傳遞時帶來的除錯與理解成本。你會看到如何使用 record、init、required、with 運算式、不可變集合與模式比對,把「修改物件」改寫成更容易追蹤、測試與維護的資料轉換。
本書不是要你放棄物件導向,也不是要把所有程式碼都改成函數式風格。相反地,它關注的是更務實的問題:在現有 C# 專案中,哪些資料適合保持不可變?哪些地方仍然應該保留可變物件?當資料需要跨越 API、資料庫、背景流程與測試案例時,怎樣的型別設計能讓程式碼更可靠?
目標讀者與先備知識
本書適合已經具備 C# 開發經驗,並希望改善資料模型設計、API 設計與狀態管理方式的開發者。
先備知識
閱讀本書之前,讀者需要具備一些 C# 開發經驗,了解並用過以下語法特性:
- 物件導向基礎:類別(class)、介面(interface)、繼承與封裝。
- 現代 C# 語法與特性:LINQ、async/await 非同步設計、可為空參考型別(nullable reference types)。
你不需要預先具備函數式程式設計(functional programming)或進階型別理論的背景知識,也不需要預先熟悉領域驅動設計(Domain-Driven Design, DDD)或特定的分層架構。書中若使用到 domain model、application layer、repository 等常見名詞,都會在首次出現時簡要說明。
適合閱讀本書的情境
如果你曾經遇過以下情況,本書能提供你一些調整設計和實作的點子:
- 一個物件被多個方法、服務、或系統分層改來改去,最後很難確認資料到底是在哪裡改動、被誰改壞。
- 知道
record、init、with、required等語法,但不確定它們在實際系統設計中該如何組合運用。 - 設計 Web API 的 request / response DTO 時,常在可變 class、record class、或 readonly struct 之間猶豫不決。
- 你知道不可變資料有其優點,但在實務上不知道如何以比較好的方式來更新深層巢狀(deeply nested)的資料結構。
- 想在不可變設計與真實世界的框架限制之間取得平衡,例如 ORM(如 Entity Framework Core)、JSON 序列化、UI 資料繫結、或效能敏感的程式碼。
本書架構
本書分為六章,以訂單處理系統作為貫穿全書的主要範例。之所以選擇訂單系統,是因為它同時涉及一些常見的設計議題:狀態轉換、API 輸入輸出資料、集合、驗證、資料持久化、以及狀態建模(state modeling)。
- 第 1 章 從可變物件到不可變資料:從最基本的問題切入:為什麼可變物件在小型程式碼中直覺方便,卻在規模擴大後越來越難追蹤狀態?本章奠定全書主旨:從「原地修改物件」,換成「從舊版本建立新版本」的寫法。
- 第 2 章 C# records、init 與不可變集合:詳細介紹現代 C# 中用來建構不可變資料的核心語法:
record class、record struct、init、required、with運算式,以及不可變集合的選擇指南。本章會特別強調一個常見陷阱:用了record並不代表資料真的不可變。 - 第 3 章 用資料轉換取代原地修改:全書核心。深入討論如何以資料轉換取代原地修改、如何判斷行為適合放在型別內或外部服務,並透過業務規則驗證、轉換管線、以及外部相依性的處理,展示不可變設計在業務流程中的實際寫法。
- 第 4 章 API、DTO 與系統邊界的資料模型:把討論重心從領域模型(domain model)轉向 Web API、資料傳輸與設定情境。探討 request/response DTO、System.Text.Json 整合、驗證位置的選擇、DTO 與 domain model 的分離、command object、event payload、以及應用程式組態物件(configuration object),說明為何這些地方很適合採用不可變設計。
- 第 5 章 不可變設計的取捨與導入:全書的綜合評估與實務總結。深入分析不可變資料在哪些位置最容易產生效益,又會帶來哪些成本。釐清可追蹤性、測試、與並行讀取的適用範圍,並討論封裝、記憶體配置、深層更新、ORM、序列化、UI 資料繫結與強封裝物件。最後提供漸進導入順序與決策參考表,協助你在可變與不可變之間做出務實抉擇。
- 第 6 章 進階選讀:用型別排除非法狀態:當 enum、旗標與 nullable 欄位已經讓非法狀態難以避免時,可以進一步用狀態型別、聯合型別(union types [C# 15])以及模式比對建模,並比較封閉階層(closed hierarchy [C# 15])的適用情境與遷移成本。若第 3 章的單一
Orderrecord 對你來說已經足夠清楚,可以略過這章。
閱讀建議
建議依序閱讀第 1 至第 5 章。前三章建立不可變資料與資料轉換的核心觀念,第 4 章示範最容易落實不可變設計的場景:DTO 與資料合約;第 5 章整理適用場景、成本、與漸進導入方式。至此已構成完整的主要學習路徑。第 6 章是進階選讀,只有在狀態複雜度較高時才需要進一步研讀。
閱讀程式碼時,請留意每個範例想要呈現的設計意圖,而不只是語法本身。不可變資料設計的重點不在於把所有屬性都改成唯讀,而是在於讓資料的生命週期、狀態轉換與使用責任更清楚。
若你想搭配實作練習,可以下載本書的範例程式,照著章節中的改寫步驟逐步執行測試。或者,閱讀本書的任何時候突然有靈感,想到目前的專案某處似乎有值得改用不可變設計的資料模型或狀態轉換流程,就動手改看看,或者下指示讓 AI agent 替你修改程式碼;藉由觀察修改前後的程式碼差異來協助理解。不必一次到位;每次只要讓一組 DTO、一個 value object、或一段資料流程更可靠,就已經得到實際收益。
閱讀裝置建議:建議優先使用電腦或平板來閱讀本書,以獲得較佳的程式碼與圖表閱讀體驗。若使用電子書閱讀器,則建議選擇較大尺寸的裝置。
技術環境與開發工具
若要跟著本書實作練習與執行範例程式碼,環境需求如下:
- 核心環境(第 1 至第 5 章): 以 C# 14 與 .NET 10 為基準開發。書中絕大多數設計原則與語法特性,在 C# 10(.NET 6)以上環境皆能適用。不過,部分範例使用較新的語法或 API,在舊版本中需要調整。例如,第 1 章使用的
[]集合運算式需要 C# 12 或更新版本;第 1 至第 5 章的範例專案以 .NET 10 為目標框架。 - 進階選讀環境(第 6 章): 第 6 章有用到 C# 15 的語法(union types 與 closed hierarchies),所以需要支援 C# 15 的 .NET 11 Preview SDK,並將語言版本設為
preview。書中亦會說明在舊版本中的替代做法。 - 開發工具: Visual Studio 2026、Visual Studio Code、JetBrains Rider,或其他支援現代 .NET 的 IDE/編輯器。
範例程式
本書的範例程式放在 GitHub 平台,網址如下:
https://github.com/ippobooks/csharp-immutable-data-design-samples
書寫慣例
有些術語若翻成中文反而容易失真或增加理解成本,因此本書會視情況保留英文,例如 SynchronizationContext、ThreadPool、ExecutionContext 等名詞。第一次出現時通常會以中英並呈,之後則視上下文採用較自然、較不妨礙閱讀的寫法。