Json.net serialize/deserialize derived types?

C#JsonSerializationjson.net

C# Problem Overview


json.net (newtonsoft)
I am looking through the documentation but I can't find anything on this or the best way to do it.

public class Base
{
	public string Name;
}
public class Derived : Base
{
	public string Something;
}

JsonConvert.Deserialize<List<Base>>(text);

Now I have Derived objects in the serialized list. How do I deserialize the list and get back derived types?

C# Solutions


Solution 1 - C#

You have to enable Type Name Handling and pass that to the (de)serializer as a settings parameter.

Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);

This will result in correct deserialization of derived classes. A drawback to it is that it will name all the objects you are using, as such it will name the list you are putting the objects in.

Solution 2 - C#

If you are storing the type in your text (as you should be in this scenario), you can use the JsonSerializerSettings.

See: https://stackoverflow.com/questions/6348215/how-to-deserialize-json-into-ienumerablebasetype-with-newtonsoft-json-net

Be careful, though. Using anything other than TypeNameHandling = TypeNameHandling.None could open yourself up to a security vulnerability.

Solution 3 - C#

Since the question is so popular, it may be useful to add on what to do if you want to control the type property name and its value.

The long way is to write custom JsonConverters to handle (de)serialization by manually checking and setting the type property.

A simpler way is to use JsonSubTypes, which handles all the boilerplate via attributes:

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}

Solution 4 - C#

Use this JsonKnownTypes, it's very similar way to use, it just add discriminator to json:

[JsonConverter(typeof(JsonKnownTypeConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

Now when you serialize object in json will be add "$type" with "base" and "derived" value and it will be use for deserialize

Serialized list example:

[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWillView Question on Stackoverflow
Solution 1 - C#MadmenyoView Answer on Stackoverflow
Solution 2 - C#kamranicusView Answer on Stackoverflow
Solution 3 - C#rzippoView Answer on Stackoverflow
Solution 4 - C#DmitryView Answer on Stackoverflow