Как использовать десериализацию C # с иерархической структурой классов - PullRequest
3 голосов
/ 15 февраля 2011

Я пытаюсь десериализовать некоторые xml-файлы в некоторые классы, которые были упрощены до следующего:

[XmlRoot("person")]
[Serializable]
public class Person
{
    [XmlElement]
    public Toy Toy { get; set; }
}

[Serializable]
public class ActionMan : Toy
{
    [XmlElement("guns")]
    public string Guns;
}

[Serializable]

public class Doll : Toy
{
    [XmlElement("name")]
    public  String Name;
}

[XmlInclude(typeof(Doll))]
[XmlInclude(typeof(ActionMan))]
public class Toy
{
}

[TestFixture]
public class ToyTest
{
    [Test]
    public void testHierarchy()
    {
        String filePath = @"test\brother.xml";
        String sisfilePath = @"test\sister.xml";
        var serializer = new XmlSerializer(typeof(Person));
        Person brother = (Person)serializer.Deserialize(new FileStream(filePath, FileMode.Open));
        Person sister = (Person)serializer.Deserialize(new FileStream(sisfilePath, FileMode.Open));

        Assert.IsNotNull(brother);
        Assert.IsNotNull(sister);
        Assert.IsAssignableFrom(typeof(ActionMan),brother.Toy);
        Assert.IsAssignableFrom(typeof(Doll),sister.Toy);
    }
}

Я хочу использовать сериализацию c # (я знаю, что могу использовать свой собственный десериализатор) иЯ думаю, что, возможно, я просто пропускаю определенный тег, о котором я не знаю (и я уверен, что у меня есть лишние теги).

вот один из файлов xml:

<person>
  <doll>
    <name>Jill</name>
  </doll>
</person>

ошибка, которую я получаю: «Ожидается: назначается из» на третьем утверждении

Ответы [ 4 ]

1 голос
/ 15 февраля 2011

То, что я сделал, спроектировал структуру классов так, как я хочу, заполните некоторые базовые данные и затем сериализуйте их. Затем проверьте, как он сериализуется, и настройте атрибуты Xml. Если ваш класс Toy имеет только несколько производных, то вы можете десериализовать их отдельно с помощью поля action-man и поля куклы, которое может быть нулевым или нет.

В качестве альтернативы для перехода из XML-файла в класс c # я использую инструмент xsd.exe для создания .xsd файла с xsd mydata.xml, а затем из этого файла класса c # с xsd /c /l:cs mydata.xsd. Затем я изучаю данные класса, чтобы понять, как определить мой класс и какие атрибуты использовать.

ссылка на xsd инструмент от Microsoft.

1 голос
/ 15 февраля 2011

Когда я пытаюсь сериализовать вашу структуру (человек, у которого ActionMan как Игрушка), я получаю

<person>
  <Toy xsi:type="ActionMan" />
</person>

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

1 голос
/ 15 февраля 2011

Классный человек должен содержать атрибут «кукла» вместо атрибута «Игрушка», я имею в виду имя. У узла XML должно быть то же имя, что и у имени атрибута.

0 голосов
/ 15 февраля 2011

Попробуйте следующее

public class Person 
{

    public Toy toy
    {
        get
        {
            return (doll == null) ? (Toy)actionMan : (Toy)doll;
        }

    }


    public Doll doll;
    public ActionMan actionMan;
}


public class Toy 
{

}


public class Doll : Toy
{
    public String name;

}


public class ActionMan : Toy
{
    public String guns;
}

class Program
{
    static void Main(string[] args)
    {

        Person brother = new Person();
        ActionMan am = new ActionMan();
        am.guns = "Laser Beam";
        brother.actionMan = am;

        Person sister = new Person();
        Doll d = new Doll();
        d.name = "Jill";
        sister.doll = d;

        Serialize(brother, "brother.xml");
        Serialize(sister, "sister.xml");

        Person b = Deserialize("brother.xml");
        Person s = Deserialize("sister.xml");

        Console.WriteLine(((ActionMan)b.toy).guns);
        Console.WriteLine(((Doll)s.toy).name);
        Console.Read();
    }

    public static Person Deserialize(String filename)
    {
        var serializer = new XmlSerializer(typeof(Person));
        return (Person)serializer.Deserialize(new FileStream(filename, FileMode.Open));

    }

    public static void Serialize(Person p, String filename){
        Stream stream = File.Open(filename, FileMode.Create);
        XmlSerializer s = new XmlSerializer(typeof(Person));
        s.Serialize(stream, p);
        stream.Close();

    }

Вы можете расширить отсюда. Помните, что в именах атрибутов регистр имеет значение. Выходные данные сериализации

brother.xml

<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <actionMan>
    <guns>Laser Beam</guns>
  </actionMan>
</Person>

sister.xml

<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <doll>
    <name>Jill</name>
  </doll>
</Person>

Выход

Laser Beam
Jill
...