This is less about Unity and more about what you use when you want to serialize C# class data of all kinds at runtime, to later deserialize.
I have tried different techniques with .net (xml, binaryformatter) but they fall down when you change the class, particularly if you remove a variable/property.
I need to be able to change the class later on, mostly adding things, also removing legacy variables/properties, possibly renaming!
BinaryFormatter was the worst with a complex storage format and total failure when class changes made!
JSON format would be fine but there are a lot of libraries out there of varying speed, mostly I need it to handle missing/changed variables without throwing an exception.
What would you consider “correct” handling of the class definition being changed? Obviously if you do something like renaming a field, the serializer has no way of automatically knowing that it represents the same thing as it used to.
The completely-general way of handling this sort of problem is:
Serialize a version number at the start of your data
When deserializing, first look at the version number before deserializing anything else
Deserialize into whatever classes you were using at the time of that version number (note: every old version of every class must still exist in your program)
Then run some code that creates an instance of the new class based on the data in the old class, doing any conversions necessary to make the data appropriate to your new model (requires you hand-code a conversion process every time you change your classes).
A simpler approach that it’s possible to do automatically would be: “any fields that don’t exist in the serialized data get their default values; any fields that exist in the serialization but not in the class are ignored.” It’s debatable how useful this is; it’s certainly possible to change your classes in lots of ways that would make old data imported in this way unsuitable for use, even if it doesn’t actually crash during the deserialization. But for what it’s worth, I believe that’s what Unity’s built-in JSON serializer does. (Note: the built-in JSON serializer has a variety of quirks and foibles that might cause you headaches later.)
It will be impossible to predict what would suit your precise needs, especially far into the future.
However, here’s a great starting point: I recommend getting the JSON .NET from the asset store:
That will likely get you 99% of the way there, if not 100% of the way.
And you can read all the data in text mode, which is absolutely critical when debugging and developing.
Unity’s built-in JSON is really more like “tiny JSON” because it fails to support generic collections (Dicts, Lists), making it essentially useless for general-purpose serializing across any possible project. It has its place with high-performance fixed data types, but that’s about it.
Don’t reach for XML either. Now you will have TWO problems to deal with: your original problem, and now XML.
And everything that @Antistone identified above is right on target too. If you know data will change, it is incumbent on you to handle defaults and/or blank fields correctly. That’s just basic future data migration, and you can always inject a hard-fail data version number if you paint yourself into a corner and must make old data obsolete.
I’ve used it extensively with generic types. I don’t think I’ve tried Dictionaries, but I’m pretty sure it has a special case for List where it serializes it as a JSON array.
However, it does have really bizarre problems with generics in certain cases. I think it may be related to nested type params; e.g. it can handle Foo but not Foo<Bar>.
On some occasions I’ve worked around this problem by replacing the nested generic with a subclass; e.g. I declare class BarInt : Bar<int> {} and then Foo will work where Foo<Bar> did not.
I don’t have any idea why this would be a problem, but that’s what my experimentation suggests.
“only fields are serialized, and types like Dictionary are not supported.”
… and…
“The JSON Serializer does not currently support working with ‘unstructured’ JSON (i.e. navigating and editing the JSON as an arbitrary tree of key-value pairs). If you need to do this, you should look for a more fully-featured JSON library.”
Well, if you think so, go right ahead. I have already wasted my half day trying it the first time!
I don’t think “types like Dictionary” is meant to be read as “generics” (though I’ll grant it’s not particularly clear what it does mean). Fields of type List and “simple” generics can definitely be displayed in the Unity inspector.
Did you remember to add [Serializable] attribute to your custom classes?
(I also haven’t updated to Unity 2019, but I doubt they removed features from it…)
Here’s an example of a generic class I’ve been using:
[Serializable]
public class Response
{
public string message;
public RespCode code;
public bool IsSuccess() { return code == RespCode.Success; }
}
[Serializable]
public class Response<T> : Response
{
public T data;
public Response(T data, string message = "", RespCode code = RespCode.Success)
{
this.data = data;
this.message = message;
this.code = code;
}
public static Response<T> Fail(string message, RespCode code = RespCode.GeneralError)
{
return new Response<T>(default(T), message, code);
}
}
The back-end serializer logic that Unity uses for JSON is the same that they use for serializing data in the inspector. just that instead of them using binary or YAML format they use the JSON format. The default serializer doesn’t natively support Dictionaries, so neither does the JSON utility. However, it DOES support ISerializationCallbackReciever so you can write custom code to enable support for serializing special types like dictionaries.
You’re right… I remember finding a handy little UnityWiki article that laid out exactly what you had to do. He implemented it with a pair of serialized lists IIRC.
But honestly, I’d rather it just come with the serialization package.
I mean it’s not like Dictionary is some weird usual barely-used thing that only comes up from time to time in some obscure engineering contexts… it’s a Dictionary baby!!
Well thanks I think I will indeed look at JSON.net for Unity, I don’t trust Unity’s custom solutions too much! Nor have used at runtime.
Also instead of straight deserialising to class I hope I/it can handle ignoring additional/missing elements and on rare occasions accepting differently named elements with additional code!