0

I have a base class like :

public class Sensor
{
        public void Serialize(string path)
        {
            try
            {
                System.Xml.Serialization.XmlSerializer xml = new System.Xml.Serialization.XmlSerializer(this.GetType());
                using (System.IO.StreamWriter file = new System.IO.StreamWriter(System.IO.Path.GetFullPath(path)))
                {
                    xml.Serialize(file, this);
                }
            }
            catch (Exception e)
            {
                ;
            }
        }

        public static T Deserialize<T>(string path)
        {
            T loaded = default(T);
            try
            {
                System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
                using (StreamReader reader = new StreamReader(path))
                {
                    loaded = (T)deserializer.Deserialize(reader);
                }
            }
            catch (Exception e)
            {
                ;
            }
            return loaded;
        }

}

Then I have a couple of classes that derive from this:

public TemperatureSensor : Sensor {}

public PositionSensor :Sensor{}

They share some common interfaces but also implement things differently. I have a SensorController that contains a List<Sensor> with a mixture of different sensors. I want to save them to XML files and load them afterwards.

I tried a simple:

public void Load()
        {
            var files = Directory.GetFiles(directory, "*.xml");
            foreach(var file in files)
            {
                var p = CodePuzzle.Deserialize<Puzzle>(file);
            }
        }

The problem is that when the deserializer finds the <PositionSensor> it crashes (Unexpected <PositionSensor> at 2,2).. I guess it was expecting <Sensor>

How can that be done?? Loading each Sensor in the sub-class it was originally stored in??

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
javirs
  • 1,049
  • 26
  • 52
  • It's missing `XmlIncludeAttribute`. You can post error message (actually this is a vote-close reason) and look for duplicates of error or just search directly for that attribute. – Sinatr Mar 22 '19 at 15:37
  • Added the concrete error (''unexpected at .. ") What do you mean the `XmlIncludeAttribute` ?? – javirs Mar 22 '19 at 15:39
  • See e.g. this [duplicate](https://stackoverflow.com/q/3326481/1997232). – Sinatr Mar 22 '19 at 15:40
  • 1
    It might be also enough to just serialize/deserialize with base type (in your case it's `Sensor`), see [this](https://stackoverflow.com/a/32368306/1997232). – Sinatr Mar 22 '19 at 15:44
  • 1
    Damn! This worked. I added the `[XmlInclude(typeof(all my sub types))]` then saved to the BASE clase, not the actual. And when loading they get loaded as the base sensor BUT they keep the info about the actual class. If someone would write and answer I will accept it. if not I will write it myself – javirs Mar 22 '19 at 15:46
  • 1
    So, duplicate of [Serialize derived class root as base class name with type](https://stackoverflow.com/q/33567824/3744182) and [Using XmlSerializer to serialize derived classes](https://stackoverflow.com/q/1643139/3744182) then? – dbc Mar 22 '19 at 18:26

1 Answers1

0

First you should add the tag [XmlInclude(typeof(DerivedClass))] to the base Class. So it looks like:

[Serializable]
[XmlInclude(typeof(TemperatureSensor))]
[XmlInclude(typeof(PositionSensor))]
public Class Sensor 
   ....

Then when you save to xml file any of the derived class, save them as Sensor, not as the derived class.

var myTemp = new TemperatureSensor();
Sensor.saveToXML(myTemp,"myTemp.xml")

Then when reading the xml´s in as Sensor, you can still identify the subclass they actually belong to.

Sensor myImportedSensor = Sensor.Load("myTemp.xml")
// myImportedSensor is Sebsir returns true
// AND
// myImportedSensor is TemperatureSensor returns also true
javirs
  • 1,049
  • 26
  • 52