← 回筆記列表
後端
易混淆概念03
它是為了「依賴注入(DI)」而量身打造的特化武器!
- C#
- Concepts
主要建構子與建構子
它是為了「依賴注入(DI)」而量身打造的特化武器!
建構子類型
服務型大樓(Service / Repository / Controller)➔ 🎯 100% 全面換成主要建構子
這類大樓(像是 EfQuoteRepository)一輩子只需要一種出生方式——就是把 DbContext 塞進去。它們肚子裡完全不需要寫 if 判斷,全心全意做依賴注入。這時候用主要建構子,程式碼精簡到像詩一樣。
++++++
資料型大樓(Domain Entities / Models / DTO)➔ 🛡️ 保持傳統建構子
這類大樓(像是 Order、User)肚子裡裝的是商業靈魂,需要防禦欄位不能為 null、數字不能小於零、或者需要多種出生參數。這時候,老老實實用傳統寫法,才是最安全的防守。
========
主要建構子能夠完全建構子嗎?
不行,主要建構子(Primary Constructor)絕對沒辦法「全面取代」原有的建構子寫法。
限制一:它沒辦法單獨玩「多載(Overloading)」(多個建構子)
在物件導向的世界裡,我們常常需要一棟大樓有「多種不同的出生方式」。 例如:建立一個 Member(會員)物件,有時候我們需要傳入完整的資料;但有時候(像單元測試)我們只想建立一個空物件。
// 🟢 這是主要建構子(大房)
public class Member(string name, int age)
{
public string Name { get; set; } = name;
public int Age { get; set; } = age;
// 🔴 驚悚點:你想寫一個「不用傳參數」的傳統建構子?
// 你必須用 : this(...) 強制去呼叫主要建構子,幫它填預設值!不呼叫編譯器就直接把你開除!
public Member() : this("神秘嘉賓", 18)
{
// 這裡才能寫別的初始邏輯
}
}
public class Symbol
{
public string Code { get; set; }
public string Name { get; set; }
// 🚪 獨立大門 A:給證交所 API 用(天天正常出生)
public Symbol(string code, string name)
{
this.Code = code;
this.Name = name;
Console.WriteLine("從網路 API 正常創建股票物件。");
}
// 🚪 獨立大門 B:給快取或測試用(從一段加密的 JSON 字串直接還原)
// 💡 瞧!這兩個建構子各走各的路,誰也不用去呼叫誰,內部邏輯完全平行的!
public Symbol(string encryptedJson)
{
var data = MyCryptoTool.DecryptAndParse(encryptedJson); // 解密大數據
this.Code = data.Code;
this.Name = data.Name;
Console.WriteLine("從加密檔案秘密復活股票物件!");
}
}
+++++++
❌ 限制二:它沒有「肚子(Body)」可以寫複雜的防禦邏輯
傳統建構子最厲害的地方,是它自帶一個大括號 { ... } 的肉身肚子。我們可以在資料剛進大門、還沒塞給屬性之前,在肚子裡進行「安檢」或「大數據加工」。
主要建構子在 C# 12 裡是沒有肚子的!它只能做簡單的指派。
// 💻 傳統寫法:肚子裡可以翻江倒海
public class Order
{
public decimal Price { get; private set; }
public Order(decimal price)
{
// 🛡️ 防禦性程式碼:進門先安檢,不合格當場噴錯!
if (price <= 0)
throw new ArgumentException("價格不能是搶劫價!");
this.Price = price * 0.9m; // 順便打個九折
}
}
比較資料庫 EF Core 與 TypeOrm
EF Core
約定優於配置