Navorski
Navorski

Reputation: 53

JsonConvert DeserializeObject with objects with inheritance

I have for example these classes

public class JsonResult
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("myobjects")]
    public List<BaseClass> myObjects { get; set; }
}

public abstract class BaseClass
{
    [JsonProperty("name")]
    public string Name { get; set; }
}

public class FlavourOne: BaseClass
{
    [JsonProperty("number")]
    public int Number { get; set; }
    [JsonProperty("mytext")]
    public string MyText { get; set; }
}

public class FlavourTwo: BaseClass
{
    [JsonProperty("yourtext")]
    public string YourText { get; set; }
}

And i have this Json object coming in as a string

{
"name": "examplename",
"myobjects": [
    {
        "name": "myFlavourOneInstance",
        "number": 1,
        "mytext": "Text from One"
    },
    {
        "name": "myFlavourTwoInstance",
        "yourtext": "Your Text from Two"
    }
]
}

I would like to have an object from that Json string as follows

var responseObject = JsonConvert.DeserializeObject<JsonResult>(rawJsonString);

But this does not work, is there a nice and clean way to have the json into the object with inherited classes and so on?

Upvotes: 1

Views: 2881

Answers (1)

stuartd
stuartd

Reputation: 73313

Yes, you can specify the class in the Json for deserialization using TypeNameHandling.Auto (or TypeNameHandling.All, depending on your use case).

Here's an example using TypeNameHandling.Auto:

void Main() {
    var jsonResult = new JsonResult {
        Name = "test",
        myObjects = new List<BaseClass> {
            new FlavourOne {
                Name = nameof(FlavourOne),
                Number = 1,
                MyText = "Text from one" 
            },
            new FlavourTwo {
                Name = nameof(FlavourTwo),
                YourText = "Text from two"
            }
        }
    };
    
    var serializerSettings = new JsonSerializerSettings {
       TypeNameHandling = TypeNameHandling.Auto
    };

    var json = JsonConvert.SerializeObject(jsonResult, Formatting.Indented, serializerSettings);
    
    Console.WriteLine(json);
}

// Your classes here

Output:

{
  "name": "test",
  "myobjects": [
    {
      "$type": "FlavourOne, AssemblyName",
      "number": 1,
      "mytext": "Text from one",
      "name": "FlavourOne"
    },
    {
      "$type": "FlavourTwo, AssemblyName",
      "yourtext": "Text from two",
      "name": "FlavourTwo"
    }
  ]
}

This means that when deserialized, they are assigned the correct type, as long as you use the same serializer settings:

var responseObject = JsonConvert.DeserializeObject<JsonResult>(json, serializerSettings);

Note though, as per the docs:

TypeNameHandling should be used with caution when your application deserializes JSON from an external source.

This is because you don't want to let external Json create arbitrary types!

Upvotes: 3

Related Questions