換姿勢就對了!用 record 讓你的 .NET 程式碼更簡潔

當 AI 指出技術債時,意外學到 class 與 record 的差異!本文分享從 class 轉換成 record 的心得、宣告方式的改變,以及如何避免常見錯誤,讓程式碼更簡潔安全。適合想優化 .NET 專案的開發者閱讀。

Web Develop

為什麼要寫這篇文章

身為一個住在台灣的工程師,每天除了要應付用戶的各種需求、修復 Bug、還要面對自己留下的「技術債」。今天終於有空回頭收拾一下,結果 AI 還幫我上了一課,建議我把 InvoiceClass 改成 record。這下可好,本來只是想偷懶一下,結果反而學到了新東西。於是決定把這過程紀錄下來,順便跟大家分享一下 classrecord 的差異,以及什麼時候該用哪一種。


class 跟 record 到底差在哪?

簡單來說,classrecord 都是用來宣告物件型別的,但他們的設計理念和適用場景不太一樣。

class

class 是我們最熟悉的物件宣告方式,它可以包含屬性、方法、事件等等,而且通常用來表示有狀態、會變動的物件。例如:

public class InvoiceClass
{
    public string Code { get; set; }
    public string InvoiceType { get; set; }
    public double Rate { get; set; }
}

這種寫法很彈性,你可以隨時修改物件的屬性值。

record

record 則是 C# 9.0 之後才加入的新語法,它主要是用來表示「不可變(immutable)」的資料結構。也就是說,一旦宣告出來,這個物件的內容就不會再被修改。例如:

public record InvoiceRecord(string Code, string InvoiceType, double Rate);

這樣寫不僅簡潔,還能自動幫你產生 EqualsGetHashCodeToString 等方法,讓你比較物件內容時更方便。


什麼時候該用 record?

根據情境,InvoiceClass 只是用來記錄發票類型、稅碼和稅率,讀取出來後就不會再修改了。這種情況下,用 record 宣告會更合適,因為:

  1. 不可變性:資料不會被意外修改,安全性更高。
  2. 簡潔語法:一行搞定,不用寫一堆 getter/setter。
  3. 自動產生方法:比較、雜湊、轉字串都幫你寫好了。

class 真的不好嗎?

其實也不是說 class 不好,只是要看場合。如果需要頻繁修改物件的屬性,或者物件有複雜的行為(例如有方法、事件等),那還是用 class 比較合適。record 適合用來表示純資料、不可變的物件。


特別注意:宣告方式大不同

當你從 class 換成 record 後,宣告物件的語法也會跟著改變。這可不是單純把 class 改成 record 就完事了,連 new 的時候都要換個姿勢

原本的寫法(class)

var invoice1 = new InvoiceClass { Code = "AA", InvoiceType = "BB", Rate = 0.05 };

這是用物件初始化器,用大括號 {},屬性能隨便填,順序也不重要,寫起來很自由。

換成 record 後的寫法

var invoice1 = new InvoiceRecord("AA", "BB", 0.05);

這裡變成用小括號 (),而且參數順序要跟 record 宣告的順序一樣,這就是建構函式的寫法。


踩坑實錄:CS1922 錯誤

你可能會像我一樣,年紀大了(誤)一時沒注意,還是用大括號 {} 宣告,結果編譯器就跳出來說:

CS1922: Cannot initialize type 'InvoiceRecord' with a collection initializer because it does not implement 'System.Collections.IEnumerable'.

翻譯成人話:
record 不能用大括號 {} 初始化,它只能用建構函式(小括號 ())來 new。


結論

經過這一番折騰,得出一個結論:以後在宣告物件之前,先問問自己「這個物件會不會被修改?」如果不會,就大膽用 record 吧!
這樣不僅程式碼更簡潔,安全性也更高,還能讓 AI 少念你幾句(誤)。