La meilleure façon de gérer cette situation est d'utiliser un JsonConverter
personnalisé.
Avant d'arriver au convertisseur, nous devrons définir une classe pour désérialiser les données. Pour la propriété Categories
qui peut varier entre un seul élément et un tableau, définissez-la comme une List
et marquez-la avec un attribut [JsonConverter]
afin que JSON.Net sache d'utiliser le convertisseur personnalisé pour cette propriété. Je recommande également d'utiliser des attributs [JsonProperty]
pour que les propriétés membres puissent avoir des noms significatifs indépendamment de ce qui est défini dans le JSON.
class Item
{
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("timestamp")]
public int Timestamp { get; set; }
[JsonProperty("event")]
public string Event { get; set; }
[JsonProperty("category")]
[JsonConverter(typeof(SingleOrArrayConverter))]
public List Categories { get; set; }
}
Voici comment j'implémenterais le convertisseur. Remarquez que j'ai rendu le convertisseur générique afin qu'il puisse être utilisé avec des chaînes de caractères ou d'autres types d'objets selon les besoins.
class SingleOrArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(List));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject>();
}
if (token.Type == JTokenType.Null)
{
return null;
}
return new List { token.ToObject() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Voici un petit programme démontrant le convertisseur en action avec vos données d'exemple :
class Program
{
static void Main(string[] args)
{
string json = @"
[
{
""email"": ""john.doe@sendgrid.com"",
""timestamp"": 1337966815,
""category"": [
""newuser"",
""transactional""
],
""event"": ""open""
},
{
""email"": ""jane.doe@sendgrid.com"",
""timestamp"": 1337966815,
""category"": ""olduser"",
""event"": ""open""
}
]";
List list = JsonConvert.DeserializeObject>(json);
foreach (Item obj in list)
{
Console.WriteLine("email: " + obj.Email);
Console.WriteLine("timestamp: " + obj.Timestamp);
Console.WriteLine("event: " + obj.Event);
Console.WriteLine("catégories: " + string.Join(", ", obj.Categories));
Console.WriteLine();
}
}
}
Et enfin, voici le résultat de ce qui précède :
email: john.doe@sendgrid.com
timestamp: 1337966815
event: open
catégories: newuser, transactional
email: jane.doe@sendgrid.com
timestamp: 1337966815
event: open
catégories: olduser
Fiddle : https://dotnetfiddle.net/lERrmu
MODIFICATION
Si vous avez besoin d'aller dans l'autre sens, c'est-à-dire de sérialiser, tout en conservant le même format, vous pouvez implémenter la méthode WriteJson()
du convertisseur comme indiqué ci-dessous. (Assurez-vous de supprimer la surcharge de CanWrite
ou de la modifier pour retourner true
, sinon WriteJson()
ne sera jamais appelé.)
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
List list = (List)value;
if (list.Count == 1)
{
value = list[0];
}
serializer.Serialize(writer, value);
}
Fiddle : https://dotnetfiddle.net/XG3eRy