深入剖析 C# 文本連接
在Tim Corey的"C#應用程式從開始到完成"系列的第11課中,Tim講解如何使用基於文字的資料連接將資料儲存至文字檔案。 Tim首先提醒觀眾,在上一堂課中,他們已設定了SQL連接並執行了重要的清理工作。 現在,重點轉向文字連接,目標明確:讓文字連接像SQL連接一樣工作,系統可以接收一個PrizeModel並正確地用ID填寫回傳。 Tim強調視頻將展示一個完整的工作流程,使用純文字檔案來儲存、讀取和更新資料。
解決方案 — 設定文字連接
Tim從打開DataAccess資料夾中的文字連接器開始。 他刪除範例代碼並從頭開始。 他解釋說,與SQL不同,文字檔案不提供像自動增量ID這樣的智慧資料庫功能。 所以第一個任務是決定在哪裡儲存文字檔案。
Tim提出一個乾淨的設計:每個模型儲存在自己的文字檔案中。例如,PrizeModel會有自己的名為PrizeModels.csv的檔案,而其他模型如MatchupModel則各有不同的檔案。 Tim將這個結構比喻為SQL表格 — 每個檔案成為一個包含該模型列表的"表格"。 這樣可以輕鬆管理資料,避免不同模型類型混在一起。
連接字串 — 儲存檔案路徑
Tim解釋說,您不僅儲存一個檔案名稱,而是儲存所有檔案將被保存的資料夾路徑。 這個路徑被放置在app.config的appSettings下。 Tim增加了一個新的鍵值對:
-
Key: filePath
- Value: 檔案儲存位置的資料夾路徑
他強調使用正確的Windows語法,並避免在路徑末尾加上斜線,因為他更喜歡在構建完整的檔案路徑時才加上斜線。 這個設定至關重要,因為它使應用程式具有彈性—如果儲存位置改變,您只需更新app.config。
計劃 — 文字連接如何運作
Tim為保存獎品制定了一個清晰的計劃:
-
讀取包含所有獎品的文字檔案。
-
將文字行轉換為PrizeModel列表。
-
找到列表中最高的ID,並設定新的ID = 最高ID + 1。
-
將新的獎品模型添加到列表中。
-
將獎品列表轉換回文字行。
- 將列表保存回文字檔案,覆蓋舊數據。
Tim解釋說,與SQL資料庫相比,文字檔案是"愚蠢的"。 SQL可以自動管理ID,但文字檔案需要開發者手動實現邏輯。 這就是為什麼Tim將過程分解成更小的方法以保持代碼清晰和重用的原因。
創建一個新類別 — 文字連接處理器
Tim創建了一個名為TextConnectorProcessor的新類別。 他將其放置在DataAccess資料夾中,但設置在不同的命名空間內以避免擁擠主要命名空間。 Tim解釋說命名空間是靈活的,可以定制,但他建議保持簡單和乾淨。
他使這個類別為public static,並開始構建幫助方法。
擴展方法 — 完整檔案路徑
Tim創建了一個擴展方法:
public static string FullFilePath(this string fileName)
這個方法將app.config中的filePath與檔案名稱結合生成完整的檔案路徑。 Tim演示瞭如何使用ConfigurationManager.AppSettings["filePath"],並解釋了在C#字串中需要轉義斜線的必要性(使用\)。
他然後將此方法轉換為擴展方法,以便可以這樣使用:
"PrizeModels.csv".FullFilePath()
Tim解釋說,這個擴展方法只在文字連接器中需要,所以他將它保留在一個單獨的命名空間中,以避免在解決方案的各處顯示。
載入檔案方法 — 讀取文字資料
接下來,Tim創建了另一個擴展方法:
public static List<string> LoadFile(this string file)
此方法使用File.Exists()檢查檔案是否存在。 如果檔案不存在,它會返回一個空列表。如果存在,它會使用File.ReadAllLines()讀取所有行並將它們轉換成列表。
Tim強調妥善處理缺失檔案的重要性,因為這在應用程式第一次運行時很常見。
將文字轉換為獎品模型
Tim創建了一個方法,將載入的文字行轉換為PrizeModel列表:
public static List<PrizeModel> ConvertToPrizeModels(this List<string> lines)
他解釋了使用逗號分隔值(CSV),其中每行包含以逗號分隔的字段。 Tim將每行分割成列並解析為合適的數據類型:
-
ID → int.Parse()
-
PlaceNumber → int.Parse()
-
PlaceName → string
-
PrizeAmount → decimal.Parse()
- PrizePercentage → double.Parse()
Tim還解釋說,他故意允許應用程式崩潰如果數據無效。 這樣可以儘早揭示問題,而不是繼續使用已損壞的數據。
尋找最大ID
Tim返回到TextConnector並解釋如何找到最大ID:
int currentID = prizes.OrderByDescending(x => x.ID).First().ID + 1;
他指出,這會在文件為空時崩潰,所以他添加了一個檢查:
if(prizes.Count > 0)
{
currentID = prizes.OrderByDescending(x => x.ID).First().ID + 1;
}
這確保了第一個記錄會獲得ID 1。
添加模型並保存
Tim將新的獎品添加到列表中,然後將列表轉換回文字行:
public static void SaveToPrizeFile(this List<PrizeModel> models, string fileName)
他使用字串插值創建每個CSV行,並將其添加到字串列表中。 最後,他使用:
File.WriteAllLines(fileName.FullFilePath(), lines);
Tim解釋說,WriteAllLines會覆蓋檔案,這是理想的行為,因為它用更新的內容刷新數據。
返回模型
Tim以返回已分配ID的PrizeModel結束方法。 這使得新獎品在應用程式的其他部分中可用,就像SQL一樣。
測試文字連接
Tim切換到Program.cs並將資料連接從SQL改為Text。 當他運行應用程式並創建獎品時,由於記錄遺失,系統最初崩潰。 Tim快速修復了這個bug,加入了if(prizes.Count > 0)檢查,然後再運行。
他演示數據正確地保存到PrizeModels.csv檔案中,並展示該檔案可以在Notepad或Excel中打開。
最後的想法 — 擴展方法與命名空間
Tim在課程結束時提醒觀眾,擴展方法只有在包含正確命名空間時才會出現。 這避免了混亂和潛在的命名衝突。 他指出,這兩堂課為應用程式的其餘部分奠定了堅實的基礎,並為未來的開發做好了準備。
