Как сериализовать коллекцию базового типа и увидеть конкретные типы в удобном для чтения XML - PullRequest
4 голосов
/ 10 апреля 2010

У меня есть список, который заполняется объектами различных конкретных типов, которые подкласс BaseType

Я использую WCF DataContractSerializer

<Children>
    <BaseType xmlns:d3p1="http://schemas.datacontract.org/2004/07/Tasks"
              i:type="d3p1:ConcreteTypeA"></BaseType>
    <BaseType xmlns:d3p1="http://schemas.datacontract.org/2004/07/Tasks"
              i:type="d3p1:ConcreteTypeB"></BaseType>
</Children>

Есть ли способ заставить это генерировать

<Children>
    <ConcreteTypeA/>
    <ConcreteTypeB/>
</Children>

Настоящая цель состоит в том, чтобы позволить пользователям генерировать некоторый XML для загрузки в память, и пользователи имеют такой уровень квалификации, что запрос их исходного XML не будет успешным.

1 Ответ

7 голосов
/ 10 апреля 2010

DataContractSerializer не предназначен для управления выходом. Он разработан, чтобы быть быстрым, неявным и простым для присвоения класса.

То, что вы хотите, это XmlSerializer. Это дает вам гораздо больший контроль над выводом XML.

Обратите внимание, что в моем примере ниже я указал много вещей, которые могли бы быть выведены из имен свойств, но просто чтобы дать вам ощущение, что вы можете переопределить их в атрибутах. Фактически, я думаю, что весь этот класс мог бы сериализоваться очень хорошо, если бы все атрибуты были удалены и некоторые KnownTypeAttributes были применены, но я не проверял это. Я не знаю, даст ли это вам точный XML-код, который вы описали (он создаст корневой элемент над дочерними элементами), но, надеюсь, это направит вас в правильном направлении.

Атрибуты, управляющие сериализацией XML

[XmlRoot(Namespace="")]
public class MyClass {

    [XmlArray("Children")]
    [XmlArrayItem("ConcreteTypeA", typeof(ConcreteTypeA))]
    [XmlArrayItem("ConcreteTypeB", typeof(ConcreteTypeB))]
    public BaseType[] Children {
        get;
        set;
    }

}

public class BaseType {
}

public class ConcreteTypeA : BaseType {
}

public class ConcreteTypeB : BaseType {
}

РЕДАКТИРОВАТЬ: Я только что проверил, и он производит что-то очень близко к тому, что вы искали.

void Main()
{

    var mc = new MyClass();
    mc.Children = new BaseType[] {
        new ConcreteTypeA(),
        new ConcreteTypeB(),
        new ConcreteTypeA(),
        new ConcreteTypeB()
    };

    var serializer = new XmlSerializer(typeof(MyClass));

    using ( var str = new StringWriter() ) {
        serializer.Serialize(str, mc);
        str.ToString().Dump();
    }

}

... производит ... (ненужные xmlns удалены с вершины)

<MyClass>
  <Children>
    <ConcreteTypeA />
    <ConcreteTypeB />
    <ConcreteTypeA />
    <ConcreteTypeB />
  </Children>
</MyClass>
...