I have an annoying conundrum where I have multiple types being returned from an API and the only difference between them is the property names. One type will have an int of Count
the other will have an int of Customers
and another will have an int of Replies
.
Classes Example:
public class DateAndCount
{
public DateTime? Date { get; set; }
public int Count { get; set; }
}
public class DateAndCount
{
public DateTime? Date { get; set; }
public int Customers { get; set; }
}
public class DateAndCount
{
public DateTime? Date { get; set; }
public int Replies { get; set; }
}
JSON Example:
{
"count": 40,
"date": "2014-01-01T00:00:00Z"
},
{
"customers": 40,
"date": "2014-01-01T00:00:00Z"
},
{
"replies": 40,
"date": "2014-01-01T00:00:00Z"
},
Instead of having to create 3+ nearly identical classes, can I somehow just have the serializer deserialize any property name into the Count
property?
You could make a simple JsonConverter
to handle this:
class DateAndCountConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(DateAndCount));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
DateAndCount dac = new DateAndCount();
dac.Date = (DateTime?)jo["Date"];
// put the value of the first integer property from the JSON into Count
dac.Count = (int)jo.Properties().First(p => p.Value.Type == JTokenType.Integer).Value;
return dac;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use it, decorate your DateAndCount
class with a [JsonConverter]
attribute to tie the converter to your class, and deserialize as usual. Here is a demo:
class Program
{
static void Main(string[] args)
{
ParseAndDump(@"{ ""Date"" : ""2015-08-22T19:02:42Z"", ""Count"" : 40 }");
ParseAndDump(@"{ ""Date"" : ""2015-08-20T15:55:04Z"", ""Customers"" : 26 }");
ParseAndDump(@"{ ""Date"" : ""2015-08-21T10:17:31Z"", ""Replies"" : 35 }");
}
private static void ParseAndDump(string json)
{
DateAndCount dac = JsonConvert.DeserializeObject<DateAndCount>(json);
Console.WriteLine("Date: " + dac.Date);
Console.WriteLine("Count: " + dac.Count);
Console.WriteLine();
}
}
[JsonConverter(typeof(DateAndCountConverter))]
class DateAndCount
{
public DateTime? Date { get; set; }
public int Count { get; set; }
}
Output:
Date: 8/22/2015 7:02:42 PM
Count: 40
Date: 8/20/2015 3:55:04 PM
Count: 26
Date: 8/21/2015 10:17:31 AM
Count: 35