从c#基类反序列化XML到派生对象

本文关键字:派生 对象 XML 反序列化 基类 | 更新日期: 2023-09-27 18:01:57

我想将XML反序列化为派生对象(使用基类):

第一个XML:

<?xml version="1.0"?>
  <root>
    <elementOne>101</elementOne>
    <elementTwo>10</elementTwo>
  </root>
第二XML:

<?xml version="1.0"?>
  <root>
    <elementOne>101</elementOne>
    <elementTwo>10</elementTwo>
    <elementThree>10</elementThree>
  </root>

我有以下基类:

[XmlRoot(ElementName = "root")]
public class ResponseBase
{
}

下列派生类:

public class DerivedOneClass: ResponseBase
{
  [XmlElementAttribute("elementOne")]
  public string ElementOne {get; set;}
  [XmlElementAttribute("elementTwo")]
  public string ElementTwo {get; set;}
}
public class DerivedTwoClass: ResponseBase
{
  [XmlElementAttribute("elementOne")]
  public string ElementOne {get; set;}
  [XmlElementAttribute("elementTwo")]
  public string ElementTwo {get; set;}
  [XmlElementAttribute("elementThree")]
  public string ElementThree {get; set;}
}

但是无法使用基类反序列化,下面是代码:

(T)(new XmlSerializer(typeof(T))).Deserialize(reader);

从c#基类反序列化XML到派生对象

您需要让序列化器知道派生类。您有两个选项:

属性>
[XmlInclude(typeof(DerivedOneClass))]
[XmlInclude(typeof(DerivedTwoClass))]
[XmlRoot(ElementName = "root")]
public class ResponseBase
{
}

直接传递

(T)(new XmlSerializer(typeof(T), 
      new[]{typeof(DerivedOneClass),typeof(DerivedTwoClass)}
)).Deserialize(reader);

在序列化数据时,XmlSerializer会自动为每一项添加一个xsi:Type属性。在您的示例中,序列化器无法知道您想要反序列化的两个类中的哪一个,因此,如果您不是生成XML的人,则可能需要使用XmlDocument或类似的东西手动解析XML。

另一种方法(如果希望保留XmlSerializer)是在解析之前手动确定类型。

private static void AddTypeDefinition(XmlDocument document)
{
    const string xsiNamespaceUri = "http://www.w3.org/2001/XMLSchema-instance";
    XmlNode node = document.SelectSingleNode("root");
    if (node == null) return;
    string type = "DerivedOneClass";
    XmlNodeList nodes = node.SelectNodes("//elementThree");
    if(nodes != null && nodes.Count > 0)
        type = "DerivedTwoClass";
    var typeAttribute = node.Attributes["type", xsiNamespaceUri];
    if (typeAttribute != null) continue;
    XmlAttribute attribute = document.CreateAttribute("xsi", "type", xsiNamespaceUri);
    attribute.Value = type;
    node.Attributes.Append(attribute);
}

可以这样使用:

XmlSerializer serializer = new XmlSerializer(typeof(ResponseBase));
XmlDocument document = new XmlDocument();
document.Load(stream);
AddTypeDefinition(document);
XmlReader reader = new XmlNodeReader(originalDocument);
ResponseBase result = serializer.Deserialize(reader) as ResponseBase;

dotNetFiddle.net的概念验证