I have two classes that have the same parent class as below:
public class Parent
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
}
public class ChildInteger : Parent
{
public int Value { get; set; } = 0;
}
public class ChildDateTime : Parent
{
public DateTime Value { get; set; } = DateTime.MinValue;
}
Now I have an API that returns a JSON string of type array containing objects of types ChildInteger, ChildDateTime.
JSON string:
[{"Value":1,"Name":"Child Integer 1","Type":"Integer"},{"Value":"2020-08-31T08:29:11.9002559+05:30","Name":"Child DateTime 1","Type":"DateTime"}]
How to de-serialize back to correct types, so that value property is not lost?
The below way will not work because value property is lost.
List parentList1 = new List(); parentList1 = JsonConvert.DeserializeObject<List>(json);
Note: These classes are from third-party API. So need to achieve it without modifying classes.
Why not try something like this:
public class Parent
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
}
public class ChildInteger : Parent
{
public int Value { get; set; } = 0;
}
public class ChildDateTime : Parent
{
public DateTime Value { get; set; } = DateTime.MinValue;
}
public static void Main()
{
var json = "[{\"Value\":1,\"Name\":\"Child Integer 1\",\"Type\":\"Integer\"},{\"Value\":\"2020-08-31T08:29:11.9002559+05:30\",\"Name\":\"Child DateTime 1\",\"Type\":\"DateTime\"}]";
List<Parent> jarray = JArray.Parse(json).AsEnumerable().Select<JToken, Parent>(x => {
switch(x["Type"].ToObject<string>())
{
case "Integer":
return x.ToObject<ChildInteger>();
case "DateTime":
return x.ToObject<ChildDateTime>();
}
return null;
}).ToList();
Console.WriteLine(jarray.Count()); // prints 2
foreach(var p in jarray) {
Console.WriteLine(p.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetValue(p));
}
// prints
// 1
// 08/31/2020 02:59:11
}
Note: I had to add inheritance for the Child types that was missing in your listing and change Date
property to Value
for ChildDateTime
.
There are many solutions to this. Assuming you didn't want an explicit converter, and wanted discrete types, don't want to use object or dynamic, then you could use JsonSubTypes . It should be noted, this would be a little more applicable to more complicated schemas... However, Add pepper and salt to taste
Given
[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(ChildInteger), "Integer")]
[JsonSubtypes.KnownSubType(typeof(ChildDateTime), "DateTime")]
public abstract class Child
{
[JsonProperty("type")]
public virtual string Type { get; }
public string Name { get; set; }
public abstract string GetValue();
}
public class ChildInteger : Child
{
public override string Type => "Integer";
public int Value { get; set; }
public override string GetValue()
=> Value.ToString();
}
public class ChildDateTime : Child
{
public override string Type => "DateTime";
public DateTime Value { get; set; }
public override string GetValue()
=> Value.ToString();
}
Usage
var input = "[{\"Value\":1,\"Name\":\"Child Integer 1\",\"Type\":\"Integer\"},{\"Value\":\"2020-08-31T08:29:11.9002559+05:30\",\"Name\":\"Child DateTime 1\",\"Type\":\"DateTime\"}]";
var results = JsonConvert.DeserializeObject<List<Child>>(input);
foreach (var item in results)
Console.WriteLine($"{item.Name}, {item.GetValue()}");
Output
Child Integer 1, 1
Child DateTime 1, 08/31/2020 02:59:11
If your goal is to only deserialized your JSON with different value types, may be you can prefer to use dynamic
property. Reference: Using type dynamic .
public class Parent
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public dynamic Value { get; set; }
}
Deserialize normally var result = JsonConvert.DeserializeObject<List<Parent>>(json);
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.