You are close. Try using ItemTypeNameHandling
instead of TypeNameHandling
:
[JsonProperty("items", ItemTypeNameHandling = TypeNameHandling.All)]
public List<Item> Items = new List<Item>();
Question
I have the following situation (for this question):
Like this LINQPad program:
void Main()
{
var doc = new Document();
doc.Items.Add(new ItemA { Name = "Test Name" });
doc.Items.Add(new ItemB { Value = 42 });
string json = JsonConvert.SerializeObject(doc, Newtonsoft.Json.Formatting.Indented).Dump();
JsonConvert.DeserializeObject<Document>(json).Dump();
}
[JsonObjectAttribute("doc")]
public class Document
{
[JsonProperty("items")]
public List<Item> Items = new List<Item>();
}
public abstract class Item { }
public class ItemA : Item
{
[JsonProperty("name")]
public string Name { get; set; }
}
public class ItemB : Item
{
[JsonProperty("value")]
public int Value { get; set; }
}
This program fails with this exception on the call to DeserializeObject
:
JsonSerializationException: Could not create an instance of type UserQuery+Item. Type is an interface or abstract class and cannot be instantiated. Path 'items[0].name', line 4, position 14.
I tried adding the TypeHandling
property to the JsonProperty
of Items
:
[JsonProperty("items", TypeNameHandling = TypeNameHandling.All)]
public List<Item> Items = new List<Item>();
but this produces this Json:
{
"items": {
"$type": "System.Collections.Generic.List`1[[UserQuery+Item, LINQPadQuery]], mscorlib",
"$values": [
which is not quite what I wanted, as it specifies the type for the list, but not for each item, however I can't seem to figure out if and how this can be done.
By this I want the following type of Json:
{
"items": [
{
"$type": "UserQuery+ItemA, LINQPadQuery",
"name": "Test Name"
},
{
"$type": "UserQuery+ItemB, LINQPadQuery",
"value": 42
}
]
}
Do I need to introduce a wrapper object with a simple property of type Item
with that attribute on instead?
Solution
You are close. Try using ItemTypeNameHandling
instead of TypeNameHandling
:
[JsonProperty("items", ItemTypeNameHandling = TypeNameHandling.All)]
public List<Item> Items = new List<Item>();