Serialize objects with inheritance by defining serialize method only in base class?

2.6k views Asked by At

I am currently doing a game in C# (for studies purpose). I'm trying to implement a Load/Save feature, which consist of saving every data of the game in a file, and the user can be able to reload the game saved after.

In the game I have a nation class attached to each players, and every nation inherit from Nation. For the moment, I have only apply the ISerializable interface on the base class, Nation, because subclasses only have method override and no new attributes to serialize.

[Serializable()]
public abstract class Nation : ISerializable 
{
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // save attributes
    }

    public Nation() { } // default constructor, to be able to do "new NationDwarf()" for example.

    // Deserialization constructor.
    public Nation(SerializationInfo info, StreamingContext ctxt)
    {
        // retrieve attributes
    }
}

public class NationDwarf : Nation {
    // some methods override
}
public class NationViking : Nation {
    // some methods override
}

The saving seems fine. But when I'm trying to retrieve data with this method (unserialization), I get an exception (the first player has a NationDwarf):

SerializationException

The constructor is missing for deserialize an object of type 'SmallWorld.NationDwarf'.

So, my question is : do I need to specify for each subclass that it's serializable and redefine each method (GetObjectData and the constructor) ? Is there a way to keep polymorphism and serialize every subclass, and of course be capable to get the correct type at deserialization?

I didn't find any solutions, except redefine the serialization method on each subclass, which is a bit heavy...

Thanks,

2

There are 2 answers

0
Mike Johnson On BEST ANSWER

You just need to provide the serialization constructor and make the GetObjectData virtual in the base class so you can override it in the child classes.

public NationDwarf(SerializationInfo info, StreamingContext context)
    : base(info, context)
{
}

While the ISerializable interface is passed on from the base class, the runtime still needs to know how to make an instance of the derived class specifically.

1
Marc Gravell On

Short version: yes. If you implement ISerializable then your implementation should be virtual and overridden by every (and again: every) subclass.

Options:

  • use BinaryFomatter, implement ISerializable, and do that
  • use BinaryFormatter but don't implement ISerializable
  • don't use BinaryFormatter

I dont mind saying that I usually advocate the last option. BinaryFormatter has... kinks. Personally I'd use protobuf-net, but: I'm biased (I'm the author)