将XML反序列化为基类c#中的派生对象

时间:2016-08-11 06:28:29

标签: c# xml abstract-class xml-deserialization

我想将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);

1 个答案:

答案 0 :(得分:2)

您需要让序列化程序了解派生类。 你有两种选择:

<强>属性

[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;

Proof of concept on dotNetFiddle.net