- Home /
Add an array to a class that has been Serialized with BinaryFormatter
Hi. I have a class to store player data in it before closing the game:
class PlayerData
{
public bool v1;
public int v2 = 1;
public int v4 = 20;
public int[] v4 = new int[50];
}
Everything works fine with loading and saving data. But now I need to add an array of type bool to this class so next time I'm using this data I can use this array and change its values. So I add this variable to "PlayerData" class and now I have this:
class PlayerData
{
public bool v1;
public int v2 = 1;
public int v4 = 20;
public int[] v4 = new int[50];
//new variable
public bool[] v5 = new int[50];
}
Problem is that when I load the old data that has been saved before adding new variable to "PlayerData" class, I can't use the new added array unless I delete the old data file because when I load the old file into my new "PlayerData" object it kinda replace the old "PlayerData" class into the new object and ignore the new array. So when I want to use this array I get the error: "NullReferenceException: Object reference not set to an instance of an object"
Everything works ok when I add am variable but looks like I can't add an object(the new array)! And I don't know why? So what should I do?
Save method:
public void Save()
{
if( loadedPlayerData!=null )
{
BinaryFormatter bf = new BinaryFormatter ();
FileStream playerFile = File.Create (Application.persistentDataPath + "/data.abc");
bf.Serialize (playerFile, playerDataObject);
playerFile.Close ();
}
}
load method:
public bool Load()
{
if (File.Exists (Application.persistentDataPath + "/data.abc")) {
BinaryFormatter bf = new BinaryFormatter ();
FileStream playerFile = File.Open (Application.persistentDataPath + "/data.abc", FileMode.Open);
playerDataObject= new PlayerData();
playerDataObject= (PlayerData)bf.Deserialize (playerFile);
playerFile.Close ();
return true;
}
else {
playerDataObject= new PlayerData();
return false;
}
}
I need to do this without losing any data, so I can't delete or ignore the old file.
Answer by Bunny83 · Apr 20, 2020 at 03:36 AM
I don't know why so many people use the BinaryFormatter for save game files. It has no real advantages but just countless disadvantages and issues compared to any other serialization method. The BinaryFormatter is generally not version tolerant. If your assemblies are not signed and do not have a strong name (RSA token) that's not a big issue. However apart from that the Binary formatter is not tolerant of missing or additional data that is not reflected in the actual class. That's why almost all serious programmers strongly recommend to not use the BinaryFormatter at all for such things.
Technically there are ways to use serialization surrogates to kind of workaround the issue. However it means you essentially roll large parts of the serialization yourself. You have to handle missing data yourself in the surrogate. If you have more than 2 different versions of your serialized data this becomes increasingly complex. Also using surrogates makes the whole process even slower.
Apart from the "strictness" of the BinaryFormatter it's also rather slow and the generated serialized data is quite verbose. For small data objects the binary stream generated most the time is even larger than JSON for example. Many people pick the BinaryFormatter thinking it protects the data from being manipulated. However the format used by the BinaryFormatter is a common well described format. (It's using the MS Remoting protocol which is used for RPCs and other serialization needs).
Rolling your own binary format would be much smaller and since you can omit all the metadata that the binary formatter puts into the stream it's also a bit harder to understand. Of course if you need / want to support different versions you have to take care of that yourself.
I would strongly recommend to just use Unity's JsonUtility which has the JsonUtility.FromJsonOverwrite method which essentially allows "mix-ins". If you want to make it "harder to read" / manipulate you can just run the result through a base64 encode or just through deflate which would make the file even smaller.
ps: thost two lines are bad code and it seems you did not understand what the Deserialize method actually did:
playerDataObject= new PlayerData();
playerDataObject= (PlayerData)bf.Deserialize (playerFile);
Creating a new PlayerData instance is pointless since you replace it with another instance that is created by the binaryformatter. That's actually the point of the binaryformatter. It's there to exactly recreate the object as it was stored. That's why all the necessary metadata is actually stored alongside the data. So the whole description of your class and structure is part of the serialized data.
Thank you very much for your answer. I managed to solve the problem and I guess I have to keep using this method for this project but I will not use BinaryFormatter for such a saving again.
Your answer
Follow this Question
Related Questions
Save and load serialization problem 0 Answers
Saving data through FileStream DataInfo? Think i'm misunderstanding something. 1 Answer
When attempting to serialize and save a jagged array it gives me an error message 1 Answer
serialization stream supports seeking but its length is 0 0 Answers
Multiple Cars not working 1 Answer