Json.net serialize/deserialize derived types?

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?

136863 次浏览

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

See: how to deserialize JSON into IEnumerable<BaseType> with Newtonsoft JSON.NET

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

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.

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; }
}

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"}
]

just add object in Serialize method

 var jsonMessageBody = JsonSerializer.Serialize<object>(model);