Reputation: 4124
I got a JSON response like:
{
"items": [
{
"document": {
"id": "123",
"title": "title2",
"description": "Description1",
"type": "Typ1"
}
},
{
"document": {
"id": "456",
"title": "title2",
"description": "desctiption2",
"type": "Type2",
"Type2Property": "Type2Property"
}
}
]
}
As you can see above I have two values (just for example) with different properties. In my code, I have two classes.
public class Type1
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Type { get; set; }
}
public class Type2
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public string Type2Property {get; set;}
}
Question: How can I create one generic list which combines Type1 and Type2. In the future, I can have more TypeX (with different properties). So, I'd like to parse JSON into a generic list.
Update: I can filter json by the Type property from the JSON.
Upvotes: 0
Views: 135
Reputation: 22849
One way to solve this problem is to create a custom JsonConverter
and override its ReadJson
method.
I've introduced a couple of helper classes to be able to parse the whole sample json:
public class TopLevel
{
public MidLevel[] Items { get; set; }
}
public class MidLevel
{
public IDocument Document { get; set; }
}
[JsonConverter(typeof(DocumentTypeConverter))]
public interface IDocument
{
}
IDocument
marker interface. If you wish you can use abstract class
.JsonConverterAttribute
and specified there the custom converter.Type1
and Type2
classes to implement this interface:public class Type1 : IDocument
{
...
public string Type { get; set; }
}
public class Type2 : IDocument
{
...
public string Type { get; set; }
public string Type2Property { get; set; }
}
The DocumentTypeConverter
naive implementation would look like this:
(Obviously you can make more type-safe)
public class DocumentTypeConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
=> throw new NotImplementedException();
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
switch (jObject["type"].Value<string>())
{
case "Typ1":
{
var obj = new Type1();
serializer.Populate(jObject.CreateReader(), obj);
return obj;
}
case "Type2":
{
var obj = new Type2();
serializer.Populate(jObject.CreateReader(), obj);
return obj;
}
default:
throw new Exception();
}
}
public override bool CanConvert(Type objectType)
=> objectType == typeof(IDocument);
}
CanConvert
tells us that this convert can be used against IDocument
s.Populate
instead of JsonCovert.Deserialize
to avoid infinite recursion.Finally, the usage is that simple:
static void Main(string[] args)
{
var sampleJson = File.ReadAllText("sample.json");
var sample = JsonConvert.DeserializeObject<TopLevel>(sampleJson);
Console.ReadLine();
}
Upvotes: 1