1

I have the following piece of code creating an object and writing into a file and reading from that file and trying to deserialize it into the same object(The code may look pointless but I simplified the large code into a small sample code to highlight the issue):

internal class Program
{
    private static void Main(string[] args)
    {
        string filePath = Path.Combine(@"C:\Users\user1", "TestFile.txt");

        TemplateA templateA = new TemplateA();
        templateA.objectsList = new List<TemplateX>();

        TemplateX templateX = new TemplateX();
        templateX.property1 = "Sample Value X1";

        TemplateY templateY = new TemplateY();
        templateY.property1 = "Sample value Y1";
        templateY.property2 = "Sample value Y2";

        templateA.objectsList.Add(templateX);
        templateA.objectsList.Add(templateY);

        string json = JsonConvert.SerializeObject(templateA, Formatting.Indented);
        File.WriteAllText(filePath, json);

        string jsonString = File.ReadAllText(filePath);
        TemplateA templateACopy = JsonConvert.DeserializeObject<TemplateA>(jsonString);
    }
}

internal class TemplateA
{
    [JsonProperty(PropertyName = "objectsList")]
    public List<TemplateX> objectsList;
}


internal class TemplateX
{
    [JsonProperty(PropertyName = "property1")]
    public string property1;
}

internal class TemplateY : TemplateX
{
    [JsonProperty(PropertyName = "property2")]
    public string property2;
}

When I read back the same object templateA written to TextFile.txt into templateACopy, it is loosing the information of property Y2("Sample value Y2"). That is templateACopy has: templateACopy object contents

This can be corrected by manually checking the string if it has elements of Class TemplateY and deserializing with the appropriate object type. But is there a way to autodetect the object is of an inherited type and deserialize into the appropriate object by the Newtonsoft JsonConvert's functions itself? (It is not known prior whether the json string has objects of TemplateX or TemplateY type. This can change at runtime.)

Romonov
  • 8,145
  • 14
  • 43
  • 55
  • [Take a look at this.](http://stackoverflow.com/a/12641541/656243) – Lynn Crumbling Dec 28 '15 at 20:41
  • `TemplateA` has no knowledge of or relation to/with `TemplateY`. You can add Y-Objects to the objectsList because they inherit from `TemplateX` – Ňɏssa Pøngjǣrdenlarp Dec 28 '15 at 20:41
  • You can also enable `TypeNameHandling.Auto`, but it's going to produce non-standardized json, and embed the types in your output. That means that if you ever change the type names, your deserializer will fail. If that's acceptable, it is another option. [This second answer](http://stackoverflow.com/a/23999085/656243) discusses using this approach. – Lynn Crumbling Dec 28 '15 at 20:43
  • So, basically you can write a custom JsonConverter, or enable `TypeNameHandling.Auto.` – Lynn Crumbling Dec 28 '15 at 20:48
  • You can add a field to the TemplateA class which is the actual type. Then do something like: TemplateA templateACopy = JsonConvert.DeserializeObject(jsonString); – Avia Dec 28 '15 at 21:03

1 Answers1

1

Use a custom setting for List<baseType> to get the derived type serialized by specifying the TypeNameHandling to objects:

   var settings = new JsonSerializerSettings()
   {
      TypeNameHandling = TypeNameHandling.Objects
   };

   string json = JsonConvert.SerializeObject(templateA, settings);

   TemplateA templateACopy = 
            JsonConvert.DeserializeObject<TemplateA>(jsonString, settings);
vendettamit
  • 14,315
  • 2
  • 32
  • 54