简体   繁体   中英

c# serialize tree of objects

I have application, which must contain map. To realize this task I create some classes:

1. Map (contains Image and two objects of Location class)
2. GPSPoint (contains two objects of ICoordinate)
3. ImagePoint (contains two int variables)
4. Location (contains GPSPoint and ImagePoint)

And one interface, and two classes, which realize it:

1. ICoordinate
2. GpsCoordinateDeg
3. GpsCoordinateDegMinSec

All of them implements ISerialization interface and have public void GetObjectData(SerializationInfo, StreamingContext) methods.

I want to save my map in the file, and I realize one of the methods of serialization, but it isn't work - I get void xml file:

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

I use my class for serialization in this code:

[Serializable]
class Map : ISerializable {
    ...
    public void saveInFile(string filepath) {
        Serializer serializer = new Serializer();
        serializer.SerializeObject(this, filepath);
    }
    ...
}

This is code of my Serializer :

class Serializer {
    public void SerializeObject<T>(T serializableObject, string fileName) {
        if (serializableObject == null) { return; }

        try {
            XmlDocument xmlDocument = new XmlDocument();
            XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
            using (MemoryStream stream = new MemoryStream()) {
                serializer.Serialize(stream, serializableObject);
                stream.Position = 0;
                xmlDocument.Load(stream);
                xmlDocument.Save(fileName);
                stream.Close();
            }
        } catch (Exception ex) {
            //Log exception here
        }
    }

    public T DeSerializeObject<T>(string fileName) {
        if (string.IsNullOrEmpty(fileName)) { return default(T); }

        T objectOut = default(T);

        try {
            string attributeXml = string.Empty;

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(fileName);
            string xmlString = xmlDocument.OuterXml;

            using (StringReader read = new StringReader(xmlString)) {
                Type outType = typeof(T);

                XmlSerializer serializer = new XmlSerializer(outType);
                using (XmlReader reader = new XmlTextReader(read)) {
                    objectOut = (T)serializer.Deserialize(reader);
                    reader.Close();
                }

                read.Close();
            }
        } catch (Exception ex) {
            //Log exception here
        }

        return objectOut;
    }
}

Where is the problem?

As i dont know the complete implementation of your poco classes i suggest you to look further to your GPSPoint class:

GPSPoint (contains two objects of ICoordinate)

You can not serialize an interface. The problem is that an interface is an opaque type. There is no way for the serializer to know what to write out and more importantly what to create when it needs to serialize things back.

You may look into StackOverflow for "serializing interfaces"-postings. I hope it helps.

Bad idea going for generics with serialization since it heavily relies on object boxing and unboxing.

My way of doing this does not rely on implementing ISerializable , rather on the careful use of attributes.

Decorate each class below with [Serializable()], [XmlType(AnonymousType=true)], [XmlRoot(Namespace="", IsNullable=false)] . The enum stands for coordinate types. Derive your existing classes from these ones. Mark properties you do not want serialized with [XmlIgnore] in your derived classes. Make Coordinate below implement your ICoordinate .

public partial class Location {
    [XmlElement]
    public GPSPoint GPSPoint { get; set; }
    [XmlElement]
    public ImagePoint ImagePoint { get; set; }
}

public partial class GPSPoint {
    [XmlElement(ElementName = "Coordinate", Order = 0)]
    public Coordinate Coordinate1 {get; set; }
    [XmlElement(Order=1, ElementName="Coordinate")]
    public Coordinate Coordinate2 {get;set;}
}

public partial class Coordinate {        
    [XmlAttribute()]
    public ICoordinateType type {get;set;}
}

[Serializable]
public enum ICoordinateType {        
    /// <remarks/>
    GpsCoordinateDegMinSec,        
    /// <remarks/>
    GpsCoordinateDeg,
}

  public partial class Map {
    [XmlElement(Order=0, IsNullable=true)]
    public object Image { get; set; }        
    /// <remarks/>
    [XmlElement(ElementName="Location", Order = 1)]
    public Location Location1 {get; set; }        
    /// <remarks/>
    [XmlElement(ElementName = "Location", Order = 2)]
    public Location Location2 {get; set; }
}

This is tested and running:

    var tc1 = new xyz.Coordinate () {type = xyz.ICoordinateType.GpsCoordinateDeg};
    var tc2 = new xyz.Coordinate () {type = xyz.ICoordinateType.GpsCoordinateDegMinSec};
    var l1 = new xyz.Location() {
        GPSPoint = new xyz.GPSPoint() { Coordinate1 = tc1, Coordinate2 = tc2 },
                ImagePoint = new xyz.ImagePoint() { x = 0, y = 0 } };

        xyz.Map m = new xyz.Map() {
            Image = null, 
            Location1 = l1,
            Location2 = new xyz.Location() {
                GPSPoint = new xyz.GPSPoint() {
                    Coordinate1 = tc1, Coordinate2 = tc2 },
                ImagePoint = new xyz.ImagePoint() { x = 1, y = 2 }
            } };

       XmlSerializer xs = new XmlSerializer(typeof(Map));
       using (var fs = File.Create("map.xml") ) { xs.Serialize(fs, m); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM