将XML反序列化为具有相同元素名称的派生类?

时间:2014-08-08 15:06:05

标签: c# xml inheritance asp.net-web-api deserialization

我的XML格式如下:

<TaskList>
<Task type="TaskA"/>
<Task type="TaskB"/>
</TaskList>

我正在尝试反序列化为类似的类:

public class TaskList
{
    [XmlElement(ElementName = "Task", Type = typeof(Task))]
    public Task[] Task { get; set; } 
}

[XmlInclude(typeof(TaskA))]
[XmlInclude(typeof(TaskB))]
[XmlRoot(ElementName = "Task")]
public class Task
{
    //Common Fields
}

public class TaskA : Task
{
    //Specific stuff
}

public class TaskB : Task
{
    //Specific stuff
}

尝试反序列化:

TaskList taskList = (TaskList)new XmlSerializer(typeof(TaskList)).Deserialize(new StringReader(xmlString));

在这个配置中,它会给我所有的任务作为基本类型“任务”。如何让它使用派生类?

1 个答案:

答案 0 :(得分:1)

如果xml看起来像这样,XmlSerializer可以将类型考虑在内:

<?xml version="1.0" encoding="utf-16"?>
<TaskList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Task xsi:type="TaskA" />
  <Task xsi:type="TaskB" />
</TaskList>

请注意,类型信息保存在特殊名称空间中。 但是,由于您无法控制xml格式,因此您必须在IXmlSerializable上实施TaskList并自行完成肮脏的工作。

就个人而言,xml很简单,我会使用LinqToXml。

static Task TaskFromElement(XElement element) {
  switch (element.Attribute("type").Value) {
    case "TaskA":
      return new TaskA();
    case "TaskB":
      return new TaskB();
    default:
      throw new NotImplementedException();
  }
}

var doc = XDocument.Parse(@"<TaskList>
  <Task type=""TaskA""/>
  <Task type=""TaskB""/>
</TaskList>");
var tasks = from e in doc.Descendants("Task")
            select TaskFromElement(e);
var taskList = new TaskList { Task = tasks.ToArray() };