C#使用XmlSerializer序列化Student类反序列化为List报错解决方案问询
问题根源
- 格式不匹配:你使用
XmlSerializer生成的是XML格式数据,并非CSV格式,文件后缀命名错误。 - 成员可访问性错误:
Student类的字段均为私有级别,XmlSerializer默认仅支持序列化公共成员,无法正确读写私有字段。 - 集合操作逻辑错误:
List<Student>是集合类型,不能直接为集合设置studentID等属性,需要先实例化单个Student对象再添加到集合中。 - 序列化写入逻辑错误:你采用追加模式每次写入单个
Student对象,每次序列化都会自动生成XML声明节点,导致最终文件存在多个XML声明,不符合XML语法规范,因此反序列化抛出异常。 - 类型匹配错误:
studentID为int类型,不能直接赋值文本框的字符串内容,需要做类型转换。
修复方案
关于你提到的XmlWriter.Create方案:如果确实需要用该方法追加写入单个节点,需要手动移除每次生成的XML声明,并且自定义统一根节点包裹所有Student元素,实现复杂度远高于下方推荐方案,不建议使用。
方案1:修正XML序列化逻辑(适合需要XML格式的场景)
第一步:修正Student类定义
[Serializable] public class Student { // 改为公共字段,也可加[XmlElement]特性修饰私有字段 public int studentID; public string studentName; public string studentAge; }
第二步:正确序列化逻辑
直接序列化List<Student>集合类型,每次写入覆盖整个文件,避免多XML声明问题:
// 1. 构造新的Student对象 Student newStudent = new Student() { studentID = int.Parse(txt_sID.Text), studentName = txt_sName.Text, studentAge = txt_sAge.Text }; // 2. 读取现有集合数据(如果文件存在) List<Student> students = new List<Student>(); string filePath = @"students.xml"; // 后缀改为xml匹配格式 if (File.Exists(filePath)) { using (FileStream fs = new FileStream(filePath, FileMode.Open)) { XmlSerializer listSerializer = new XmlSerializer(typeof(List<Student>)); students = (List<Student>)listSerializer.Deserialize(fs); } } // 3. 添加新对象到集合并全量写入文件 students.Add(newStudent); using (TextWriter writer = new StreamWriter(filePath)) { XmlSerializer listSerializer = new XmlSerializer(typeof(List<Student>)); listSerializer.Serialize(writer, students); }
第三步:反序列化逻辑
List<Student> students = new List<Student>(); string filePath = @"students.xml"; if (File.Exists(filePath)) { using (FileStream fs = new FileStream(filePath, FileMode.Open)) { XmlSerializer listSerializer = new XmlSerializer(typeof(List<Student>)); students = (List<Student>)listSerializer.Deserialize(fs); } }
方案2:真实CSV序列化方案(更适合轻量列表存储)
CSV格式无复杂节点,读写性能更好,适合扁平类数据存储,完全匹配你最初的文件格式需求:
写入逻辑
Student newStudent = new Student() { studentID = int.Parse(txt_sID.Text), studentName = txt_sName.Text, studentAge = txt_sAge.Text }; string filePath = @"students.csv"; // 首次写入添加表头,后续仅追加数据 bool needHeader = !File.Exists(filePath); using (StreamWriter sw = new StreamWriter(filePath, true, Encoding.UTF8)) { if (needHeader) { sw.WriteLine("studentID,studentName,studentAge"); } // 处理含逗号、双引号的特殊字段,用双引号包裹 sw.WriteLine($"{newStudent.studentID},\"{newStudent.studentName.Replace("\"", "\"\"")}\",{newStudent.studentAge}"); }
读取逻辑
List<Student> students = new List<Student>(); string filePath = @"students.csv"; if (File.Exists(filePath)) { string[] lines = File.ReadAllLines(filePath, Encoding.UTF8); // 跳过表头行 for (int i = 1; i < lines.Length; i++) { string line = lines[i].Trim(); if (string.IsNullOrEmpty(line)) continue; string[] parts = line.Split(','); students.Add(new Student() { studentID = int.Parse(parts[0].Trim()), studentName = parts[1].Trim('"').Replace("\"\"", "\""), studentAge = parts[2].Trim() }); } }
内容的提问来源于stack exchange,提问作者ItsDano
相关产品推荐
相关产品推荐

