[{"data":1,"prerenderedAt":401},["ShallowReactive",2],{"note-\u002Fnotes\u002Fsync\u002Fcsharp-03":3},{"id":4,"title":5,"body":6,"category":388,"date":389,"description":19,"draft":390,"extension":391,"meta":392,"navigation":108,"path":393,"seo":394,"sourcePath":395,"stem":396,"tags":397,"__hash__":400},"notes\u002Fnotes\u002Fsync\u002Fcsharp-易混淆概念-易混淆概念03.md","易混淆概念03",{"type":7,"value":8,"toc":379},"minimark",[9,13,20,24,29,32,35,39,42,45,49,54,58,61,152,274,277,281,284,287,357,360,364,368,373,375],[10,11,12],"h2",{"id":12},"主要建構子與建構子",[14,15,16],"blockquote",{},[17,18,19],"p",{},"它是為了「依賴注入（DI）」而量身打造的特化武器！",[21,22,23],"h3",{"id":23},"建構子類型",[25,26,28],"h4",{"id":27},"服務型大樓service-repository-controller-100-全面換成主要建構子","服務型大樓（Service \u002F Repository \u002F Controller）➔ 🎯 100% 全面換成主要建構子",[17,30,31],{},"這類大樓（像是 EfQuoteRepository）一輩子只需要一種出生方式——就是把 DbContext 塞進去。它們肚子裡完全不需要寫 if 判斷，全心全意做依賴注入。這時候用主要建構子，程式碼精簡到像詩一樣。",[17,33,34],{},"++++++",[25,36,38],{"id":37},"資料型大樓domain-entities-models-dto-️-保持傳統建構子","資料型大樓（Domain Entities \u002F Models \u002F DTO）➔ 🛡️ 保持傳統建構子",[17,40,41],{},"這類大樓（像是 Order、User）肚子裡裝的是商業靈魂，需要防禦欄位不能為 null、數字不能小於零、或者需要多種出生參數。這時候，老老實實用傳統寫法，才是最安全的防守。",[17,43,44],{},"========",[21,46,48],{"id":47},"主要建構子能夠完全建構子嗎","主要建構子能夠完全建構子嗎?",[14,50,51],{},[17,52,53],{},"不行，主要建構子（Primary Constructor）絕對沒辦法「全面取代」原有的建構子寫法。",[25,55,57],{"id":56},"限制一它沒辦法單獨玩多載overloading多個建構子","限制一：它沒辦法單獨玩「多載（Overloading）」（多個建構子）",[17,59,60],{},"在物件導向的世界裡，我們常常需要一棟大樓有「多種不同的出生方式」。\n例如：建立一個 Member（會員）物件，有時候我們需要傳入完整的資料；但有時候（像單元測試）我們只想建立一個空物件。",[62,63,68],"pre",{"className":64,"code":65,"language":66,"meta":67,"style":67},"language-csharp! shiki shiki-themes github-light github-dark","\u002F\u002F 🟢 這是主要建構子（大房）\npublic class Member(string name, int age)\n{\n    public string Name { get; set; } = name;\n    public int Age { get; set; } = age;\n\n    \u002F\u002F 🔴 驚悚點：你想寫一個「不用傳參數」的傳統建構子？\n    \u002F\u002F 你必須用 : this(...) 強制去呼叫主要建構子，幫它填預設值！不呼叫編譯器就直接把你開除！\n    public Member() : this(\"神秘嘉賓\", 18) \n    {\n        \u002F\u002F 這裡才能寫別的初始邏輯\n    }\n}\n","csharp!","",[69,70,71,79,85,91,97,103,110,116,122,128,134,140,146],"code",{"__ignoreMap":67},[72,73,76],"span",{"class":74,"line":75},"line",1,[72,77,78],{},"\u002F\u002F 🟢 這是主要建構子（大房）\n",[72,80,82],{"class":74,"line":81},2,[72,83,84],{},"public class Member(string name, int age)\n",[72,86,88],{"class":74,"line":87},3,[72,89,90],{},"{\n",[72,92,94],{"class":74,"line":93},4,[72,95,96],{},"    public string Name { get; set; } = name;\n",[72,98,100],{"class":74,"line":99},5,[72,101,102],{},"    public int Age { get; set; } = age;\n",[72,104,106],{"class":74,"line":105},6,[72,107,109],{"emptyLinePlaceholder":108},true,"\n",[72,111,113],{"class":74,"line":112},7,[72,114,115],{},"    \u002F\u002F 🔴 驚悚點：你想寫一個「不用傳參數」的傳統建構子？\n",[72,117,119],{"class":74,"line":118},8,[72,120,121],{},"    \u002F\u002F 你必須用 : this(...) 強制去呼叫主要建構子，幫它填預設值！不呼叫編譯器就直接把你開除！\n",[72,123,125],{"class":74,"line":124},9,[72,126,127],{},"    public Member() : this(\"神秘嘉賓\", 18) \n",[72,129,131],{"class":74,"line":130},10,[72,132,133],{},"    {\n",[72,135,137],{"class":74,"line":136},11,[72,138,139],{},"        \u002F\u002F 這裡才能寫別的初始邏輯\n",[72,141,143],{"class":74,"line":142},12,[72,144,145],{},"    }\n",[72,147,149],{"class":74,"line":148},13,[72,150,151],{},"}\n",[62,153,155],{"className":64,"code":154,"language":66,"meta":67,"style":67},"public class Symbol\n{\n    public string Code { get; set; }\n    public string Name { get; set; }\n\n    \u002F\u002F 🚪 獨立大門 A：給證交所 API 用（天天正常出生）\n    public Symbol(string code, string name)\n    {\n        this.Code = code;\n        this.Name = name;\n        Console.WriteLine(\"從網路 API 正常創建股票物件。\");\n    }\n\n    \u002F\u002F 🚪 獨立大門 B：給快取或測試用（從一段加密的 JSON 字串直接還原）\n    \u002F\u002F 💡 瞧！這兩個建構子各走各的路，誰也不用去呼叫誰，內部邏輯完全平行的！\n    public Symbol(string encryptedJson)\n    {\n        var data = MyCryptoTool.DecryptAndParse(encryptedJson); \u002F\u002F 解密大數據\n        this.Code = data.Code;\n        this.Name = data.Name;\n        Console.WriteLine(\"從加密檔案秘密復活股票物件！\");\n    }\n}\n",[69,156,157,162,166,171,176,180,185,190,194,199,204,209,213,217,223,229,235,240,246,252,258,264,269],{"__ignoreMap":67},[72,158,159],{"class":74,"line":75},[72,160,161],{},"public class Symbol\n",[72,163,164],{"class":74,"line":81},[72,165,90],{},[72,167,168],{"class":74,"line":87},[72,169,170],{},"    public string Code { get; set; }\n",[72,172,173],{"class":74,"line":93},[72,174,175],{},"    public string Name { get; set; }\n",[72,177,178],{"class":74,"line":99},[72,179,109],{"emptyLinePlaceholder":108},[72,181,182],{"class":74,"line":105},[72,183,184],{},"    \u002F\u002F 🚪 獨立大門 A：給證交所 API 用（天天正常出生）\n",[72,186,187],{"class":74,"line":112},[72,188,189],{},"    public Symbol(string code, string name)\n",[72,191,192],{"class":74,"line":118},[72,193,133],{},[72,195,196],{"class":74,"line":124},[72,197,198],{},"        this.Code = code;\n",[72,200,201],{"class":74,"line":130},[72,202,203],{},"        this.Name = name;\n",[72,205,206],{"class":74,"line":136},[72,207,208],{},"        Console.WriteLine(\"從網路 API 正常創建股票物件。\");\n",[72,210,211],{"class":74,"line":142},[72,212,145],{},[72,214,215],{"class":74,"line":148},[72,216,109],{"emptyLinePlaceholder":108},[72,218,220],{"class":74,"line":219},14,[72,221,222],{},"    \u002F\u002F 🚪 獨立大門 B：給快取或測試用（從一段加密的 JSON 字串直接還原）\n",[72,224,226],{"class":74,"line":225},15,[72,227,228],{},"    \u002F\u002F 💡 瞧！這兩個建構子各走各的路，誰也不用去呼叫誰，內部邏輯完全平行的！\n",[72,230,232],{"class":74,"line":231},16,[72,233,234],{},"    public Symbol(string encryptedJson)\n",[72,236,238],{"class":74,"line":237},17,[72,239,133],{},[72,241,243],{"class":74,"line":242},18,[72,244,245],{},"        var data = MyCryptoTool.DecryptAndParse(encryptedJson); \u002F\u002F 解密大數據\n",[72,247,249],{"class":74,"line":248},19,[72,250,251],{},"        this.Code = data.Code;\n",[72,253,255],{"class":74,"line":254},20,[72,256,257],{},"        this.Name = data.Name;\n",[72,259,261],{"class":74,"line":260},21,[72,262,263],{},"        Console.WriteLine(\"從加密檔案秘密復活股票物件！\");\n",[72,265,267],{"class":74,"line":266},22,[72,268,145],{},[72,270,272],{"class":74,"line":271},23,[72,273,151],{},[17,275,276],{},"+++++++",[25,278,280],{"id":279},"限制二它沒有肚子body可以寫複雜的防禦邏輯","❌ 限制二：它沒有「肚子（Body）」可以寫複雜的防禦邏輯",[17,282,283],{},"傳統建構子最厲害的地方，是它自帶一個大括號 { ... } 的肉身肚子。我們可以在資料剛進大門、還沒塞給屬性之前，在肚子裡進行「安檢」或「大數據加工」。",[17,285,286],{},"主要建構子在 C# 12 裡是沒有肚子的！它只能做簡單的指派。",[62,288,290],{"className":64,"code":289,"language":66,"meta":67,"style":67},"\u002F\u002F 💻 傳統寫法：肚子裡可以翻江倒海\npublic class Order\n{\n    public decimal Price { get; private set; }\n\n    public Order(decimal price)\n    {\n        \u002F\u002F 🛡️ 防禦性程式碼：進門先安檢，不合格當場噴錯！\n        if (price \u003C= 0) \n            throw new ArgumentException(\"價格不能是搶劫價！\");\n            \n        this.Price = price * 0.9m; \u002F\u002F 順便打個九折\n    }\n}\n",[69,291,292,297,302,306,311,315,320,324,329,334,339,344,349,353],{"__ignoreMap":67},[72,293,294],{"class":74,"line":75},[72,295,296],{},"\u002F\u002F 💻 傳統寫法：肚子裡可以翻江倒海\n",[72,298,299],{"class":74,"line":81},[72,300,301],{},"public class Order\n",[72,303,304],{"class":74,"line":87},[72,305,90],{},[72,307,308],{"class":74,"line":93},[72,309,310],{},"    public decimal Price { get; private set; }\n",[72,312,313],{"class":74,"line":99},[72,314,109],{"emptyLinePlaceholder":108},[72,316,317],{"class":74,"line":105},[72,318,319],{},"    public Order(decimal price)\n",[72,321,322],{"class":74,"line":112},[72,323,133],{},[72,325,326],{"class":74,"line":118},[72,327,328],{},"        \u002F\u002F 🛡️ 防禦性程式碼：進門先安檢，不合格當場噴錯！\n",[72,330,331],{"class":74,"line":124},[72,332,333],{},"        if (price \u003C= 0) \n",[72,335,336],{"class":74,"line":130},[72,337,338],{},"            throw new ArgumentException(\"價格不能是搶劫價！\");\n",[72,340,341],{"class":74,"line":136},[72,342,343],{},"            \n",[72,345,346],{"class":74,"line":142},[72,347,348],{},"        this.Price = price * 0.9m; \u002F\u002F 順便打個九折\n",[72,350,351],{"class":74,"line":148},[72,352,145],{},[72,354,355],{"class":74,"line":219},[72,356,151],{},[358,359],"hr",{},[10,361,363],{"id":362},"比較資料庫-ef-core-與-typeorm","比較資料庫 EF Core 與 TypeOrm",[21,365,367],{"id":366},"ef-core","EF Core",[14,369,370],{},[17,371,372],{},"約定優於配置",[358,374],{},[376,377,378],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":67,"searchDepth":81,"depth":81,"links":380},[381,385],{"id":12,"depth":81,"text":12,"children":382},[383,384],{"id":23,"depth":87,"text":23},{"id":47,"depth":87,"text":48},{"id":362,"depth":81,"text":363,"children":386},[387],{"id":366,"depth":87,"text":367},"backend","2026-08-09",false,"md",{},"\u002Fnotes\u002Fsync\u002Fcsharp-03",{"title":5,"description":19},"C#\u002F易混淆概念\u002F易混淆概念03.md","notes\u002Fsync\u002Fcsharp-易混淆概念-易混淆概念03",[398,399],"C#","Concepts","RYybNrYxvXY6W2KO7zcP63SRBLWsO15KZ28Jud1Nnh4",1788767747520]