XML-сериализация производных классов - PullRequest
1 голос
/ 12 октября 2009

У меня есть массив элементов, которые мне нужно сериализовать с помощью XmlSerializer. Проблема у меня в том, что у меня есть 2 производных класса, и их сериализация, чтобы они имели имя элемента общей базы, похоже, не работает.

Итак, как должен выглядеть XML:

<Root>
    <Base> foo </Base>
</Root>

Вместо этого я получаю

<Root>
    <Derived1> foo </Derived1>
</Root>

Код для массива элементов, который я сериализую, -

private object[] m_nodes;

[System.Xml.Serialization.XmlElementAttribute("Base", typeof(Derived1)]
[System.Xml.Serialization.XmlElementAttribute("Base", typeof(Derived2)]

public object[] Nodes
{
    get
    {
        return this.m_nodes;
    }
    set
    {
        this.m_nodes = value;
    }
}

С помощью приведенного выше кода я получаю ошибку отражения от узлов. Если я изменю «Base» в обоих атрибутах XmlEelementAttributes на «Derived1» и Derived2 », это будет работать, но имя элемента будет неправильным.

[System.Xml.Serialization.XmlInclude(typeof(Derived1))]
public abstract class Base
{
    public Base()
    {

    }
}



[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public class Derived1: Base
{
    public Derived1()
    {

    }
}

Любая помощь очень ценится. Спасибо.

Ответы [ 3 ]

5 голосов
/ 12 октября 2009

Сериализация XML включает процедуры сериализации и десериализации. Следовательно, если вам действительно удалось это сделать, то сериализатор не сможет определить, какой тип использовать при десериализации полученной структуры XML. Исходя из моего опыта, лучше либо использовать два разных имени, либо использовать собственный сериализатор / десериализатор с использованием классов XmlWriter и XmlReader.

1 голос
/ 12 октября 2009

Дэвид ответил правильно. Это невозможно с голой XmlSerialization, поскольку она не может определить, какой из производных классов должен быть создан при десериализации из содержимого элемента XML.

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

Настраиваемая сериализация с использованием XmlReader / Writer всегда возможна, но она требует больше времени, чем простая XmlSerialization (особенно, если вы не являетесь опытным наркоманом XML!)

Что я делаю в таких случаях, так это создаю промежуточную иерархию классов и пишу простые преобразования в коде. Итак, исходные объекты сначала преобразуются в промежуточную структуру, которая может быть обработана с помощью XmlSerialization.

Например, в вашем случае вы можете создать класс, аналогичный Base (я называю его BaseSerializable), и заполнить в нем данные Derived1 и Derived2. BaseSerializable может быть обработан с помощью XmlSerialization. При десериализации вы получаете BaseSerializable из XmlSerialization, а затем определяете (используя содержимое полей / свойств), какой из классов Derived1 / Derived2 должен быть создан. Таким образом, на практике вы кодируете очень небольшую часть сериализации с помощью пользовательского кода, а оставшуюся часть оставляете библиотеке XmlSerialization.

0 голосов
/ 14 ноября 2011

После долгого поиска альтернатив я обнаружил следующую запись здесь о переполнении стека: Как использовать XmlSerializer для десериализации объекта, который может иметь базовый или производный класс, не зная заранее типа?

Я попробовал, и это работает, также для сериализации. Так что при сериализации это также дает хороший вывод. Для массива вам нужно использовать атрибут XmlArrayItem.

...