Base Class & Implementations
public abstract class BaseFoo
{
public string FooBarBuzz { get; set; }
}
public class AFoo : BaseFoo
{
public string A { get; set; }
}
public class BFoo : BaseFoo
{
public string B { get; set; }
}
When we deserilize it we need somehow a “marker”-property and I use the “FooBarBuzz” property from the BaseFoo-class as my marker. If it contains “A”, then it is implementation “AFoo” and “B” for “BFoo”.
Serialize
The serialization part works as expected:
AFoo a = new AFoo();
a.FooBarBuzz = "A";
a.A = "Hello World";
BFoo b = new BFoo();
b.FooBarBuzz = "B";
b.B = "Hello World";
List<BaseFoo> allFoos = new List<BaseFoo>();
allFoos.Add(a);
allFoos.Add(b);
var result = JsonConvert.SerializeObject(allFoos);
Resulting Json:
Deserialize and boom…
If we continue now and just use the typical code we get a nice exception:
var test = JsonConvert.DeserializeObject<List<BaseFoo>>(result);
Exception:
Additional information: Could not create an instance of type ConsoleApplication6.BaseFoo. Type is an interface or abstract class and cannot be instantiated. Path ‘[0].A’, line 1, position 6.
Introducing a simple JsonConverter
The exception is pretty clear, because JSON.NET has no knowledge about our convention. The way to go* is to write a JsonConverter. I found a couple of implementations on StackOverflow, but this one seems to be the easiest and best option.
* Small Update based on the comment from Michael: JSON.NET can also include the TypeName in the JSON as a “$type” property. If this is not an issue for you, then just add the “TypeNameHandling.Auto” to the JsonSerializerSettings and it will work. In my actual scenario I want a clean JSON output, without JSON.NET magic. That’s the reason for the converter.
public class FooConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(BaseFoo));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo["FooBarBuzz"].Value<string>() == "A")
return jo.ToObject<AFoo>(serializer);
if (jo["FooBarBuzz"].Value<string>() == "B")
return jo.ToObject<BFoo>(serializer);
return null;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
When we read the JSON we look for our “FooBarBuzz”-property and serialize it to the correct implementation.
Let’s use our new JsonConverter
Just create a new instance of the Converter and apply it to the DeserializeObject method and you are done.
JsonConverter[] converters = { new FooConverter()};
var test = JsonConvert.DeserializeObject<List<BaseFoo>>(result, new JsonSerializerSettings() { Converters = converters });
Easy, right?
The full sample can be viewed on GitHub