当我使用 XmlTextReader 反序列化一个 XML 文档时,一个没有对应类的文本元素会被简单地忽略。
注意:这不是关于 XML 中缺少的元素,它需要存在,而是存在于 XML 文本中,同时在代码中没有等效的属性。
我本来希望得到一个异常,因为如果运行时数据中缺少相应的元素并且我稍后对其进行序列化,则生成的 XML 文档将与原始文档不同。所以忽略它是不安全的(在我的现实世界中,我刚刚忘记定义给定文档包含的 99 多个类之一,我一开始没有注意到)。
那么这是否正常,如果是,为什么?如果元素无法序列化,我可以以某种方式请求获得异常吗?
在下面的示例 XML 中,我故意拼错了“MyComandElement”来说明核心问题:
<MyRootElement>
<MyComandElement/>
</MyRootElement>
Run Code Online (Sandbox Code Playgroud)
MyRootElement.cs:
public class CommandElement {};
public class MyRootElement
{
public CommandElement MyCommandElement {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
反序列化:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyRootElement));
XmlTextReader xmlReader = new XmlTextReader(@"pgtest.xml");
MyRootElement mbs2 = (MyRootElement)xmlSerializer.Deserialize(xmlReader);
xmlReader.Close();
Run Code Online (Sandbox Code Playgroud)
正如我在进一步研究中偶然发现的那样,这个问题实际上非常容易解决,因为......
...XmlSerializer 支持事件!所要做的就是为缺少的元素定义一个事件处理程序
void Serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
throw new Exception("Unknown element "+e.Element.Name+" found in "
+e.ObjectBeingDeserialized.ToString()+" in line "
+e.LineNumber+" at position "+e.LinePosition);
}
Run Code Online (Sandbox Code Playgroud)
并使用 XmlSerializer 注册事件:
xmlSerializer.UnknownElement += Serializer_UnknownElement;
Run Code Online (Sandbox Code Playgroud)
该主题在MSDN上进行了处理,在那里人们还了解到
默认情况下,在调用 Deserialize 方法后,XmlSerializer 会忽略未知类型的 XML 属性。
毫不奇怪,还有缺少属性、节点和对象的事件。
那么这是否正常,如果是,为什么?
因为也许您正在使用其他人的 XML 文档,而他们在他们的 XML 中定义了 300 个不同的元素,您只关心两个。您是否应该被迫为所有元素创建类并反序列化所有元素,以便能够访问您关心的两个元素?
或者,您可能正在使用一个会随着时间推移而不断变化的系统。您正在编写使用当今 XML 的代码,如果稍后引入新元素/属性,它们不应该阻止您测试和部署的代码能够继续使用它们理解的 XML 部分(在此处插入警告,希望如果您处于这种情况,您/XML 作者不要稍后引入元素,这对于理解正确处理文档至关重要)。
这是同一个硬币的两个方面,为什么希望系统在遇到要求反序列化的 XML 文档中的意外部分时不会崩溃。