J'essaye de désérialiser [{"foo": "1", "bar": false}, {"foo": "2", "bar": false}]
en type List<(string, bool)>
:
JsonConvert.DeserializeObject<List<(string foo, bool bar)>>(json)
Mais obtenez toujours une liste de valeurs par défaut - (null, false)
.
Comment puis-je obtenir une désérialisation correcte?
PS Je ne suis intéressé par aucun modèle / classe à cet effet. J'ai besoin d'un tuple de valeur exactement à la place.
4 Réponses :
Je suggère d'abord de convertir le JSON
en modèle et de Deserialize
le json
var definition = new[] {new { foo = "", bar = false } }; string json = @"[{'foo': '1', 'bar': false}, {'foo': '2', 'bar': true}]"; var obj = JsonConvert.DeserializeAnonymousType(json, definition).Select(p=> (p.foo, p.bar)).ToList();
Méthode 1 - Utilisation de foreach
Dictionary<string, bool> keyValuePairs = JsonConvert .DeserializeObject<IEnumerable<item>>(json) .GroupBy(p=>p.foo, StringComparer.OrdinalIgnoreCase) .ToDictionary(x => x.First().foo, x => x.First().bar);
Méthode 2 - Utiliser LINQ
sans se soucier des doublons
Dictionary<string, bool> keyValuePairs = JsonConvert.DeserializeObject<IEnumerable<item>>(json).ToDictionary(x => x.foo, x => x.bar);
Méthode 3 - Utiliser LINQ
en tenant compte des doublons
using (StreamReader r = new StreamReader(filepath)) { string json = r.ReadToEnd(); var obj = JsonConvert.DeserializeObject<List<item>>(json); Dictionary<string, bool> keyValuePairs = new Dictionary<string, bool>(); foreach (var keyvalue in obj) { if (!keyValuePairs.ContainsKey(keyvalue.foo)) keyValuePairs.Add(keyvalue.foo, keyvalue.bar); } }
Méthode 4 - Utilisation de DeserializeAnonymousType
public class item { public string foo { get; set; } public bool bar { get; set; } }
La désérialisation vers le dictionnaire provoquera une exception si le paramètre Key (foo) est répété dans les données.
@VishweshwarKapse, ont changé le code pour éviter les exceptions
Je ne souhaite pas créer de classe factice pour cette raison. J'ai posé une question sur les tuples
@anatol, vérifiez si la méthode 4 - DeserializeAnonymousType
résout votre problème
Une façon d'y parvenir serait d'utiliser un JsonConverter. Par exemple,
foo:1,bar:False foo:2,bar:False
Vous pouvez maintenant utiliser le convertisseur comme suit.
var json = "[{'foo': '1', 'bar': false}, {'foo': '2', 'bar': false}]"; var result = JsonConvert.DeserializeObject<IEnumerable<(string,bool)>>(json,new ValueTupleConverter<string,bool>()); foreach(var (foo,bar) in result) { Console.WriteLine($"foo:{foo},bar:{bar}"); }
Exemple de sortie
public class ValueTupleConverter<U,V> : Newtonsoft.Json.JsonConverter { public override bool CanConvert(Type objectType) { return typeof(ValueTuple<U,V>) == objectType; } public override object ReadJson(Newtonsoft.Json.JsonReader reader,Type objectType,object existingValue,Newtonsoft.Json.JsonSerializer serializer) { if (reader.TokenType == Newtonsoft.Json.JsonToken.Null) return null; var jObject = Newtonsoft.Json.Linq.JObject.Load(reader); var properties = jObject.Properties().ToList(); return new ValueTuple<U, V>(jObject[properties[0].Name].ToObject<U>(), jObject[properties[1].Name].ToObject<V>()); } public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { serializer.Serialize(writer, value); } }
La fonctionnalité de tuple C # a été créée pour représenter des ensembles de valeurs, pas des entités.
Les noms des valeurs sont comme les noms des variables. Comme les noms de variables, les noms de valeurs de tuple n'existent que dans le code source.
(string foo, bool bar)
est, en fait, juste ValueTuple<string, int>
. tout comme (string bar, bool foo)
:
var json = "[{\"foo\": \"1\", \"bar\": false}, {\"foo\": \"2\", \"bar\": false}]"; var jArray = JsonConvert.DeserializeObject<JArray> (json); var list = new List<(string foo, bool bar)>(); foreach (var item in jArray) { list.Add((item.Value<string>("foo"), item.Value<bool>("bar"))); }
Les valeurs de tuples sont stockées dans des champs nommés Item1
, Item2
et ainsi de suite.
Voyez par vous-même comment cela fonctionne ici .
Si vous souhaitez utiliser des tuples de valeur pour cela, vous devrez vous désérialiser:
(string foo, bool bar) a = ('one', true); (string bar, bool foo) b = a;
En C # 9, vous pouvez créer un record
et utiliser le déconstructeur généré pour créer un ValueTuple. J'ai vu que vous ne vouliez pas déclarer de modèle mais c'est l'approche la plus proche que j'ai trouvée:
Déclarez l'enregistrement:
private record FooBar(string foo, bool bar);
Désérialiser et déconstruire:
(string foo, bool bar) = JsonConvert.DeserializeObject<FooBar>(json);
ou
var (foo, bar) = JsonConvert.DeserializeObject<FooBar>(json);
Pouvez-vous ajouter la sortie json attendue?
vérifiez ce stackoverflow.com/questions/1207731/ ... peut-être que cela peut vous aider