将 XML 反序列化为来自基础 class 的派生对象 c#

Deserialize XML to derived objects from base class c#

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

第一个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>

我有以下基地class:

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

以下派生 classes:

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

但是无法使用base反序列化class,代码如下:

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

您需要让序列化程序知道派生的 类。 你有两个选择:

属性

[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 的那个,你可能需要手动解析 XML 用 XmlDocument 或类似的东西。

另一种方法(如果您想保留 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