.NET Deserializing JSON to multiple types

nullable picture nullable · Oct 11, 2012 · Viewed 12.9k times · Source

Possible Duplicate:
Deserializing JSON into one of several C# subclasses

I have read-only access following JSON schema:

{ items: [{ type: "cat", catName: "tom" }, { type: "dog", dogName: "fluffy" }] }

I would like to deserialize each of these to their respective type:

class Cat : Animal {
    string Name { get; set; }
}
class Dog : Animal {
    string Name { get; set; }
}

My only thought at this point is to deserialize them to a dynamic object, or Dictionary<string, object> and then construct these objects from there.

I may be missing something from one of the JSON frameworks out there....

What would your approach be? =]

Answer

nick_w picture nick_w · Oct 11, 2012

I think it's likely you'll need to deserialize the Json then construct the objects from there. Deserializing directly to Cat or Dog won't be possible as the deserializer won't know how to construct these objects specifically.

Edit: borrowing heavily from Deserializing heterogenous JSON array into covariant List<> using JSON.NET

Something like this would work:

interface IAnimal
{
    string Type { get; set; }
}

class Cat : IAnimal
{
    public string CatName { get; set; }
    public string Type { get; set; }
}

class Dog : IAnimal
{
    public string DogName { get; set; }
    public string Type { get; set; }
}

class AnimalJson
{
    public IEnumerable<IAnimal> Items { get; set; }
}

class Animal
{
    public string Type { get; set; }
    public string Name { get; set; }
}

class AnimalItemConverter : Newtonsoft.Json.Converters.CustomCreationConverter<IAnimal>
{
    public override IAnimal Create(Type objectType)
    {
        throw new NotImplementedException();
    }

    public IAnimal Create(Type objectType, JObject jObject)
    {
        var type = (string)jObject.Property("type");

        switch (type)
        {
            case "cat":
                return new Cat();
            case "dog":
                return new Dog();
        }

        throw new ApplicationException(String.Format("The animal type {0} is not supported!", type));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load JObject from stream 
        JObject jObject = JObject.Load(reader);

        // Create target object based on JObject 
        var target = Create(objectType, jObject);

        // Populate the object properties 
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}

string json = "{ items: [{ type: \"cat\", catName: \"tom\" }, { type: \"dog\", dogName: \"fluffy\" }] }";
object obj = JsonConvert.DeserializeObject<AnimalJson>(json, new AnimalItemConverter());