C#控制台应用向XML数组节点追加字符串时触发carList为null的报错
空引用(carList为null)的直接诱因
xDoc2.Root.Descendants("Autokategorie").Where(...)返回的是 元素集合(IEnumerable) ,而非单个节点。后续直接对这个集合调用Descendants("carModeName")时,集合没有对应的单节点引用,最终FirstOrDefault()返回null。- 代码混用了
XmlDocument和XDocument两套独立的XML操作对象:用XDocument加载文件做修改,最后却调用XmlDocument xDoc的Save方法写文件,哪怕carList能正常取到值,修改也不会被持久化。 - 现有XML带默认命名空间(XmlSerializer生成结构时自动附带),直接按节点名
carModeName匹配时,因为未关联命名空间标识,会出现“节点名明明存在但匹配不到”的情况,直接触发空引用。 - 代码中反复修改
serializerHelper.filePath静态字段值,容易因静态值被覆盖导致文件路径错位,引发节点查找失败。
修复方案
基于现有业务逻辑调整,统一使用XDocument完成全流程操作,匹配XmlSerializer序列化规则处理节点结构:
- 先从分类节点集合中取出单个匹配的目标Autokategorie节点,再向下查找carModeName节点
- 读取XML默认命名空间,用于所有节点匹配逻辑,避免匹配失效
- 按原来
[XmlArray]的序列化结构,在carModeName节点下追加对应字符串子元素 - 用同一个XDocument对象完成保存操作,避免修改丢失
- 用局部变量存储文件路径,不依赖静态字段值,杜绝路径被意外覆盖的问题
修复后的核心代码:
public static void carAdderAfterAddingCar(int categoryId, int carId, string carCategoryName) { string categoryFilePath = "carCategoryDb.xml"; string carFilePath = "carDb.xml"; serializerHelper sHelper = new serializerHelper(); List<Auto> carLists = sHelper.showData(typeof(List<Auto>), carFilePath) as List<Auto>; // 加载分类XML文档 XDocument xCategoryDoc = XDocument.Load(categoryFilePath); // 获取文档默认命名空间(XmlSerializer生成的固定命名空间) XNamespace defaultNs = xCategoryDoc.Root.GetDefaultNamespace(); foreach (var item in carLists) { if (!item.id.Equals(carId)) continue; string temp = item.model; // 定位对应ID的分类节点(取单个匹配项,非集合) var targetCategory = xCategoryDoc.Descendants(defaultNs + "Autokategorie") .FirstOrDefault(x => x.Attribute("id").Value == categoryId.ToString()); if (targetCategory == null) { Console.WriteLine("未找到匹配ID的汽车分类"); return; } // 定位分类下的carModeName节点 var carModeNode = targetCategory.Descendants(defaultNs + "carModeName").FirstOrDefault(); if (carModeNode == null) { carModeNode = new XElement(defaultNs + "carModeName"); targetCategory.Add(carModeNode); } Console.WriteLine("Bitte geben sie die neue gebühr/Tage ein"); // 匹配XmlArray的序列化结构:在carModeName节点下追加string类型子元素 carModeNode.Add(new XElement(defaultNs + "string", temp)); // 用同一个文档对象保存修改 xCategoryDoc.Save(categoryFilePath); Console.Clear(); Console.WriteLine($"\r\n {temp} wurde der Kategorie: {carCategoryName} hinzugefügt"); break; } }
注意事项
- 原代码中
carList.Add(temp)的写法不符合序列化规则:[XmlArray]标记的字符串数组,序列化后结构为<carModeName><string>值1</string><string>值2</string></carModeName>,直接给carModeName节点加文本内容会导致后续反序列化时读不到已添加的元素。 - 不要混用
XmlDocument和XDocument两套API,两类对象完全独立,跨对象操作不会同步修改内容,会出现“明明加了节点但保存后文件没变化”的问题。 - 所有节点匹配逻辑必须关联文档的默认命名空间,否则哪怕XML里节点名完全一致,也会因为命名空间不匹配导致查找失败。
内容的提问来源于stack exchange,提问作者natyus
相关产品推荐
相关产品推荐

