user2015253
user2015253

Reputation: 1444

Can I deserialize previously serialized data after adding fields to the class?

If I have a serializable class, e.g.:

[Serializable]
public class SaveData {
   public int positionX = 42;
   public int positionY = 69;
}

and serialize it into a file using a BinaryFormatter.Serialize() and a FileStream, and later ship an update of the app with an updated class SaveData to save additional data, e.g.:

[Serializable]
public class SaveData {
   public int positionX = 42;
   public int positionY = 69;
   public string name = "Mr Foo";
}

will old saves still load properly? (again, using BinaryFormatter.Deserialize() and FileStream)

And if it works, will it use "Mr Foo" as default value?

Upvotes: 0

Views: 344

Answers (1)

user2015253
user2015253

Reputation: 1444

After @MindSwipe gave me a link to a great read in the comments, I want to provide an answer to my own question to help out future search engine users with the same question.

So if this is my SaveData class to begin with:

[Serializable]
public class SaveData {
    public int positionX = 42;
    public int positionY = 69;
}

Then, if I ship an update that adds a field to this class, I should do it like this:

[Serializable]
public class SaveData {
    public int positionX = 42;
    public int positionY = 69;

    [OptionalField(VersionAdded = 2)]
    public string name = "Mr Foo";

    [OnDeserialized()]
    private void OnDeserialized(StreamingContext sc)
    {
        // set default value for optional fields like this!
        // deserialization will not take the initialization value
        // from the field definition above!
        if(name == null) name = "Mr Foo";
    }
}

Note that all fields that are added later must have the attribute OptionalField, ideally with a VersionAdded to it.

Here a couple tips ("best practices"), provided by Microsoft in an article called Version tolerant serialization (because you never know, if that link will work forever):

  • Never remove a serialized field.
  • Never apply the NonSerializedAttribute attribute to a field if the attribute was not applied to the field in the previous version.
  • Never change the name or the type of a serialized field.
  • When adding a new serialized field, apply the OptionalFieldAttribute attribute.
  • When removing a NonSerializedAttribute attribute from a field (that was not serializable in a previous version), apply the OptionalFieldAttribute attribute.
  • For all optional fields, set meaningful defaults using the serialization callbacks unless 0 or null as defaults are acceptable.

Upvotes: 2

Related Questions