深入探讨C#文本连接
在Tim Corey的"C# App Start to Finish"系列的第11课中,Tim解释了如何使用基于文本的数据连接将数据保存到文本文件中。 Tim首先提醒观众,在上一课中,他们设置了SQL连接并执行了关键的日常工作。 现在,关注点转移到了文本连接,目标很明确:让文本连接像SQL连接一样工作,系统可以接受一个PrizeModel并返回一个ID已正确填写的模型。 Tim强调视频将展示一个完整的工作流,用于使用纯文本文件存储、读取和更新数据。
解决方案——设置文本连接
Tim首先在DataAccess文件夹中打开了Text Connector。 他删除了样例代码并从头开始。 他解释说与SQL不同,文本文件不提供类似自动增量ID的智能数据库功能。 因此,第一个任务是决定在哪里存储文本文件。
Tim提出一个干净的设计:每个模型存储在其自己的文本文件中。例如,PrizeModel将有一个自己的文件,称为PrizeModels.csv,而MatchupModel等其他模型将各有单独的文件。 Tim将这种结构与SQL表进行比较——每个文件变成一个包含该模型列表的"表"。 这使数据易于管理,并防止混合不同的模型类型。
连接字符串——存储文件路径
Tim解释说,与其存储单个文件名,不如存储保存所有文件的文件夹路径。 这个路径放在app.config中的appSettings下。 Tim添加了一个新的键值对:
键:filePath
- 值:文件将被存储的文件夹路径
他强调使用正确的Windows语法,并避免在路径末尾添加斜杠,因为他更喜欢在构建完整文件路径时才添加斜杠。 这个设置很重要,因为它使应用程序更具灵活性——如果存储位置改变,您只需更新app.config即可。
计划——文本连接如何工作
Tim为保存奖品制定了清晰的计划:
加载包含所有奖品的文本文件。
将文本行转换为PrizeModel列表。
在列表中找到最高ID,并设置新的ID=最高ID + 1。
将新的奖品模型添加到列表中。
将奖品列表转换回文本行。
- 将列表保存回文本文件,覆盖旧数据。
Tim解释说,与SQL数据库相比,文本文件是"愚蠢的"。 SQL可以自动管理ID,而文本文件则需要开发人员手动实现逻辑。 这就是为什么Tim将过程分解为小方法,以保持代码干净且可重用。
创建新类——Text Connector Processor
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更改为文本。 当他运行应用程序并创建奖项时,由于记录缺失,系统最初崩溃。 Tim迅速通过if(prizes.Count > 0)检查修复了该错误,然后再次运行。
他演示了数据正确保存在PrizeModels.csv文件中,并展示了该文件如何在记事本或Excel中打开。
最终想法——扩展方法和命名空间
Tim通过提醒观众,扩展方法仅在包含正确的命名空间时才出现,来结束课程。 这避免了混乱和潜在的命名冲突。 他指出,这两节课为应用程序的其余部分奠定了坚实的基础,并为未来的发展铺平了道路。

