XmlSerializer调用reader.Read()后终止读取及使用自身reader时中止的原因
这个问题我之前也碰到过,核心原因在于XmlSerializer.Deserialize的工作机制和StreamReader的位置管理,咱们一步步拆解:
1. XmlSerializer.Deserialize的内置读取逻辑
当你调用Deserialize(reader)时,它会从当前reader的位置开始,寻找匹配目标类型(这里是MainItem)的XML根元素,然后完整读取整个根元素的所有内容来完成反序列化。一旦这个过程完成,它会自动把reader的位置移动到根元素结束标签的后面——如果你的XML文件只有MainItem这一个根节点,那reader就直接到了流的末尾。这时候再尝试用同一个reader调用Read(),自然会因为没有更多内容而返回-1,看起来就是“中止读取”。
比如你提供的正常代码是没问题的:
var serializer = new XmlSerializer(typeof(MainItem)); using (var reader = new StreamReader(SettingFile.FullName)) { var deserializedObject = serializer.Deserialize(reader); ret = (MainItem)deserializedObject; }
这里reader初始位置在流的开头,XmlSerializer能准确找到<MainItem>根节点,读完后reader到了末尾,这是预期行为。
2. 手动调用reader.Read()的致命影响
如果在调用Deserialize之前,你手动调用了reader.Read(),哪怕只是读取一个字符,都会改变reader的当前位置。比如:
using (var reader = new StreamReader(SettingFile.FullName)) { reader.Read(); // 手动移动了reader位置 var deserializedObject = serializer.Deserialize(reader); // 这里会出问题 }
这时候XmlSerializer从偏移后的位置开始找根元素,要么找不到匹配的<MainItem>标签,要么读取到不完整的XML内容,直接导致反序列化失败或者提前终止,表现为你看到的“中止读取”。
3. 针对你的模型的额外说明
你的MainItem类定义了List<Child1>属性,对应的XML结构应该是类似这样的:
<MainItem> <Child1>...</Child1> <Child1>...</Child1> </MainItem>
XmlSerializer对根元素的匹配非常严格,只要reader的起始位置不在<MainItem>的第一个字符,它就无法正确解析整个对象,进而触发读取中止的问题。
解决建议
- 除非有特殊需求,不要在Deserialize之前手动操作reader的位置,直接传入初始状态的StreamReader即可。
- 如果必须提前读取流的内容(比如验证XML头部),读取完成后一定要把reader重置到起始位置:
reader.BaseStream.Seek(0, SeekOrigin.Begin); reader.DiscardBufferedData(); // 清空缓存,确保读取从头开始
内容的提问来源于stack exchange,提问作者Nasenbaer

