1

I am building a game in unity. I have a DataStorage parent class that is a singleton that I serialize/deserialize to save/load progress.

It looks like this:

public class DataStored
{
   // Properties

   public PlayerData Player { get; set; } = new PlayerData();
   public EnvironmentData Environ { get; set; } = new EnvironmentData();

   // Singleton

   private static DataStored current; 
   public static DataStored Current
   {
    get
    {
        if (current == null)
        {
            current = new DataStored();
        }
        return current;
    }
    set
    {
        current = value;
    }
  }
}

I load the data like this:

...
                DataStored.Current = (DataStored)bf.Deserialize(file);
...

This all works fine. And I can release my game. However, if I then need to add a new property to the DataStored singleton, e.g.:

public AppSettings Settings { get; set; } = new AppSettings();

Then this value is set initially, but then as soon as I load the game data, using the deserialize line of code above, it gets set to null (presumably because when I saved the singleton the property did not exist). What I was hoping for was the singleton would realise the property was null and then create a new instance of AppSettings for that property.

Is the only way around this to expand the code for each property I add, as follows? e.g.

private PlayerStatsData stats;
public PlayerStatsData Stats
{
    get { return stats ??= new PlayerStatsData(); }
}

I am guessing using default auto-properties ignores the instantiation if the class object is deserialized rather than constructed a fresh?

My motivation for asking this question is the wish to reduce 3 lines of code to 1 line of code for each of the many new properties I will be creating.

derHugo
  • 83,094
  • 9
  • 75
  • 115
Charlie S
  • 4,366
  • 6
  • 59
  • 97
  • what is `bf`? Is this a `BinaryFormatter`? In that case -> [**STOP using `BinaryFormatter`!!**](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide) – derHugo Nov 21 '22 at 07:31
  • And yes, in addition to the security issues it also ships along with your issue of being quite unflexible when adding/removing/modifying members afterwards .. see e.g. [here](https://stackoverflow.com/questions/3527399/binary-serialization-adding-a-new-field-to-class-will-it-work), [here](https://stackoverflow.com/questions/29676594/binary-formatter-and-properties-with-without-backing-fields), [here](https://stackoverflow.com/questions/8245501/deserialization-of-optional-fields-from-binaryformatter) etc – derHugo Nov 21 '22 at 07:36
  • Rather change to a different serialization like e.g. XML, JSON which both usually support optional fields by default (depending on the library you use of course) – derHugo Nov 21 '22 at 07:37
  • Can you show the serialization code? Maybe it will be enough to fill null fields once after deserialization? – VoidName Nov 24 '22 at 21:07

1 Answers1

0

You can add a method marked with the OnDeserializedAttribute attribute to your class like this:

[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
    if (Settings == null)
    {
        Settings = new AppSettings();
    }
}

This method will be automatically invoked by BinaryFormatter.Deserialize.

Note: As others said pay attention when using BinaryFormatter because it has been deprecated by Microsoft

Matteo Umili
  • 3,412
  • 1
  • 19
  • 31