开发者

How Do I use C# deserialization with a hierarchichal class structure

I'm trying to deserialize some xml files into some classes which hav开发者_StackOverflowe been simplified to the following:

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

I want to use the c# Serialisation (I know I can use my own deserialiser) and I think I'm perhaps simply missing a particular tag that I don't know about (and I'm sure I've got superfluous tags).

here is one fo the xml files:

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

the error I get is "Expected: assignable from " on the third assert


Class person should contain a "doll" attribute instead of a "Toy" attribute, I mean the name. The XML node must have the same name as the attribute name -casing matters.


When I try to serialize your structure (person, who has ActionMan as Toy) i get

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

I guess this is how you can handle inheritance of your types. But I guess you cant change your already serialised XML.


What I have done, is designed the class structure the way I want, fill in some basic data and then serialize it. Then examine how it serializes and adjust the Xml attributes. If your Toy class has only a few derivatives, then you can de-serialize them seperately with a action-man field and a doll field that might be null or not.

Alternatively to go from an Xml file to a c# class I use the xsd.exe tool to generate a .xsd file with xsd mydata.xml and then from that a c# class file with xsd /c /l:cs mydata.xsd. Then I examine the class data to get clues as to how to define my class and what attributes to use.

link to xsd tool from Microsoft.


Try the following

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();

    }

You can expand from here. Remember that, in the attribute names, casing matters. The serialization output I got is

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>

The output is

Laser Beam
Jill
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜