jacobz jacobz - 2 months ago 7
JSON Question

JSON infer class type based on Dictionary key

I would like to deserialize a

Dictionary<string, AbstractDataObject>
.
AbstractDataObject
is an abstract class which
SomeClass1
and
SomeClass2
inherit from. The key value of the dictionary (a string) is the name of the class:

{
"StoredData": {
"SomeClass1": {
"Foo": "Test"
},
"SomeClass2": {
"Bar": 123
}
}
}


The classes look like following (simplified):

public class Data
{
public Dictionary<string, AbstractDataObject> StoredData { get; set; }
}

public abstract class AbstractDataObject
{
}

public class SomeClass1 : AbstractDataObject
{
public string Foo { get; set; }
}

public class SomeClass2 : AbstractDataObject
{
public int Bar { get; set; }
}


How can I tell Json.NET to infer the class type based on the Dictionary key? I've looked around but I'm unsure where to start implementing this functionality

Answer

You could make a custom JsonConverter to handle this:

public class CustomDictionaryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Dictionary<string, AbstractDataObject>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var dict = new Dictionary<string, AbstractDataObject>();
        JObject jo = JObject.Load(reader);
        foreach (JProperty prop in jo.Properties())
        {
            switch (prop.Name)
            {
                case "SomeClass1":
                    dict.Add("SomeClass1", prop.Value.ToObject<SomeClass1>(serializer));
                    break;

                case "SomeClass2":
                    dict.Add("SomeClass2", prop.Value.ToObject<SomeClass2>(serializer));
                    break;
            }
        }
        return dict;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Then use it like this:

Data data = JsonConvert.DeserializeObject<Data>(json, new CustomDictionaryConverter());

Fiddle: https://dotnetfiddle.net/ba4wB6