0

I am making a text adventure game, and I am trying to store a list of all of the locations the game has to a JSON file. The locations are stored as Location objects, each of which has data such as what the name of the location is, and the text that should be printed when the location is entered. I also have a FlagLocation child class that overrides a certain method and does something different if a certain boolean property (unique to this derived class) is true.

I'm able to store a polymorphic list of both Location and FlagLocation objects under the same List<Location collection just fine, but I'm running into a problem when I try to serialize them to JSON and then convert them back. When deserializing the list, everything in the list is of type Location, and I can't access public methods or properties that are unique to FlagLocation.

Here are the classes, simplified for pastability:

    public class Location
    {
        public string Id;
        public string EntryText;

        public Location(string id, List<string> adjacents, string entryText)
        {
            Id = id;
            EntryText = entryText;
        }
        
        public virtual string GetAppropriateText()
        {
            return EntryText;
        }
    }

    public class FlaggedLocation : Location
    {
        public bool flag;
        public string AlternateEntryText;
        
        public FlaggedLocation(string id, string entryText, string altText, bool f) : base(id, adjacents, entryText)
        {
            AlternateEntryText = altText;
            flag = f;
        }

        public override string GetAppropriateText()
        {
            if (flag)
                return AlternateEntrytext;
            else
                base.GetAppropriateText();
        }
    }

And here's what I'm trying to do with them in the main method:

List<Location> locations = new List<Location>();
//add some test objects to the list
locations.Add(new Location("Start", "Welcome To The game!"));
locations.Add(new FlaggedLocation("Basement", "Welcome to the basement!", "Welcome to the ALTERNATIVE basement!", true));

//serialize the list
File.WriteAllText(@"serialized.json", JsonConvert.SerializeObject(locations));

//deserialize that file we just wrote to a new list
var stuff = JsonConvert.DeserializeObject<List<Location>>(File.ReadAllText("serialized.json"));

Console.WriteLine(stuff[1].GetAppropriateText())
//this prints "Welcome to the basement!"

which we DON'T want, since its flag variable is true, meaning it's supposed to return the contents of AlternateText. It doesn't do this because it's calling the parent class's non-overridden GetAppropriateText() method, meaning it's of type Location when it should be of type FlagLocation.

My question is this: How do I serialize and deserialize this list in such a way that the type of objects that use the child class is not lost?

  • Have you tried enabling Type Name Handling during serialization? https://stackoverflow.com/questions/8513042/json-net-serialize-deserialize-derived-types – Studwell Sep 26 '21 at 05:41
  • Worked, thank you! For anyone reading this in the future, you have to use the settings parameter both when you serialize _and_ deserialize. Could you post this as an answer so I can mark it as accepted? – johnnymcmike Sep 26 '21 at 06:24
  • Setting `TypeNameHandling` can open your app to certain security vulnerabilities. See: [TypeNameHandling caution in Newtonsoft Json](https://stackoverflow.com/q/39565954/3744182). As an alternative, you could write a custom `JsonConverter` that detects the type to deserialize based on the properties present. See: [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/3744182) or [How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?](https://stackoverflow.com/q/8030538/3744182). – dbc Sep 26 '21 at 12:28

0 Answers0