IXmlSerializable重命名元素后如何正确反序列化对应类型?
实现IXmlSerializable时,重命名XML元素后如何正确反序列化到真实类型?
问题场景
在实现IXmlSerializable接口时,已通过WriteXml方法将DataContext的序列化元素名从真实类型名(如ChartWindowViewModel)改为IViewModel,但在ReadXml方法中反序列化时,因XmlSerializer期望真实类型的元素名,导致抛出错误。
原实现代码
WriteXml代码
public void WriteXml(XmlWriter writer) { XmlRootAttribute x = new XmlRootAttribute(); x.ElementName = nameof(IViewModel); var dwserializer = new XmlSerializer(this.DataContext.GetType(), x); dwserializer.Serialize(writer, this.DataContext); }
原ReadXml代码(存在问题)
public void ReadXml(XmlReader windowReader) { var type = Type.GetType(windowReader.GetAttribute("AssemblyQualifiedName")); //此属性来自ViewModel序列化 var dwserializer = new XmlSerializer(type); var a = dwserializer.Deserialize(windowReader); //因读取到重命名的"IViewModel"元素而抛出错误 }
XML示例
重命名后的XML
<Workspace Title="WS-001" NosWorkSpaceGuid="7f81ed2e-a511-4f9d-81db-9728304dad67"> <ViewCollection> <ChartWindow AssemblyQualifiedName="CustomView.ChartWindow, ChartWindows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Top="78" Left="78" Height="1023" Width="2580"> <IViewModel AssemblyQualifiedName="CustomView.ChartWindowViewModel, ChartWindows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Guid="606a4303-4662-4092-9c92-c452fb0f2860"> <Conteners/> </IViewModel> </ChartWindow> </ViewCollection> </Workspace>
未重命名时的XML(可正常工作)
<Workspace Title="WS-001" NosWorkSpaceGuid="08f17674-f7be-418a-a388-e3fc8796cb92"> <ViewCollection> <ChartWindow AssemblyQualifiedName="CustomView.ChartWindow, ChartWindows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Top="226" Left="845" Height="1023" Width="2580"> <ChartWindowViewModel AssemblyQualifiedName="CustomView.ChartWindowViewModel, ChartWindows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Guid="276d0b1b-e3d9-4067-a56e-ecc43faaa4e4"> <Conteners/> </ChartWindowViewModel> </ChartWindow> </ViewCollection> </Workspace>
解决方案
问题核心是:ReadXml中创建XmlSerializer时未指定与WriteXml一致的根元素名。修改时需同步指定XmlRootAttribute,让序列化器识别<IViewModel>元素。
修改后的ReadXml代码
public void ReadXml(XmlReader windowReader) { // 获取真实类型 var type = Type.GetType(windowReader.GetAttribute("AssemblyQualifiedName")); // 与WriteXml保持一致,指定根元素名为IViewModel var xmlRoot = new XmlRootAttribute(nameof(IViewModel)); var dwserializer = new XmlSerializer(type, xmlRoot); // 反序列化得到真实类型实例 var viewModel = dwserializer.Deserialize(windowReader); // 直接赋值给DataContext(若DataContext为IViewModel类型,无需强制转换) this.DataContext = viewModel; // 若需操作具体类型成员,可安全转换(可选) // var concreteViewModel = viewModel as ChartWindowViewModel; // if (concreteViewModel != null) // { // // 处理具体类型逻辑 // } }
关键说明
- 同步根元素配置:必须在
ReadXml中创建XmlSerializer时传入与WriteXml相同的XmlRootAttribute,确保序列化器能匹配<IViewModel>元素。 - 类型转换问题:反序列化得到的对象本身就是
AssemblyQualifiedName指定的真实类型实例。如果DataContext是IViewModel接口类型,直接赋值即可;若需访问具体类型的专属成员,可使用as关键字进行安全转换,避免类型转换异常。
内容的提问来源于stack exchange,提问作者Zwan
相关产品推荐
相关产品推荐

