I’ve been writing code for a long time, but have only recently started learning C# and Unity.
In my game, I want to load data, such as scenarios, from files. I figured the simplest approach would be to just use the system serializer. In outline:
[Serializable]
public class Scenario : ISerializationCallbackReceiver
{
public void OnBeforeSerialize() { ... }
public void OnAfterDeserialize() { ... }
...
}
...
Scenario s = JsonUtility.FromJson<Scenario>(...);
My code works, at least when everything is going well. But I want to handle errors gracefully, in particular when the input file is correct JSON but doesn’t make sense as a Scenario. My first thought was to throw an exception from OnAfterDeserialize(), but the exception doesn’t seem to propagate all the way down to FromJson().
I can’t return an error code from OnAfterDeserialize(), because it’s void.
I could add a bool isCorrect member to each class I want to serialize, or a global deserializationErrorCode variable, but that seems inelegant.
This seems like potentially complex and ever-getting-more-complex logic. Over time you’re gonna have more things that don’t “make sense as a scenario.”
I would put that logic outside of the serializer, somewhere in a data validator.
My thinking is that you NEED this validation anyway, regardless if the data goes through your your serializer or not (i.e., if you hand-type some stuff in for testing). Why not put it in a generic “validate this scenario please” class?
Thanks. It sounds as though you’re suggesting wrapping deserialization and verification in a class method:
class Scenario : ISerializationCallbackReceiver
{
int IsValid() {
// Return 0 if self is correct, or an error code otherwise.
}
Scenario LoadFromFile(string filename)
{
string s = <load contents of file>;
Scenario retval = JsonUtility.FromJson<Scenario>(s);
if (!retval.IsValid())
throw new Exception("Invalid file contents");
return retval;
}
Just to give a bit more context: the problem that led me down this path is: my file has units that refer to each other. There’s an array of units, each of which has a unique identifier, as well as an array of IDs of the units that it references. I had a typo in one of the identifiers, so the structure described by the file had a reference to a missing unit. With an error like that, it’s best to give up early, throw an exception, and not waste time trying to parse the rest of the JSON file. Just put up an error message to the user saying, “Sorry, this file is corrupt. Please try another one.”
But if the serializer is blocking exceptions, then it seems as though the best way to handle errors is to have a member field in the object saying whether it’s valid, and if not, what the problem is. OnAfterDeserialize() can set that field as soon as it notices the error, and IsValid() can check whether the field is set.
My main problem with this approach is that it seems inelegant. Can anyone suggest a better approach?