Ich habe eine Web-API-Methode, die eine beliebige JSON-Nutzlast in eine JObject
Eigenschaft akzeptiert . Als solches weiß ich nicht, was kommt, aber ich muss es trotzdem in .NET-Typen übersetzen. Ich hätte gerne eine, Dictionary<string,object>
damit ich damit umgehen kann, wie ich will.
Ich habe viel gesucht, aber nichts gefunden und am Ende eine unordentliche Methode gestartet, um diese Konvertierung durchzuführen, Schlüssel für Schlüssel, Wert für Wert. Gibt es eine einfache Möglichkeit, dies zu tun?
Eingabe ->
JObject person = new JObject(
new JProperty("Name", "John Smith"),
new JProperty("BirthDate", new DateTime(1983, 3, 20)),
new JProperty("Hobbies", new JArray("Play football", "Programming")),
new JProperty("Extra", new JObject(
new JProperty("Foo", 1),
new JProperty("Bar", new JArray(1, 2, 3))
)
)
Vielen Dank!
ToObject(JToken)
Hilfsmethode in der ersten Antwort führt diese Konvertierung mit minimalem Code durch.Antworten:
Wenn Sie
JObject
Objekte haben, funktioniert möglicherweise Folgendes:JObject person; var values = person.ToObject<Dictionary<string, object>>();
Wenn Sie keine haben
JObject
, können Sie eine mit derNewtonsoft.Json.Linq
Erweiterungsmethode erstellen :using Newtonsoft.Json.Linq; var values = JObject.FromObject(person).ToObject<Dictionary<string, object>>();
Andernfalls weist diese Antwort möglicherweise in die richtige Richtung, da eine JSON-Zeichenfolge in ein Wörterbuch deserialisiert wird.
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
quelle
DeserializeObject<Dictionary<string, object>>
hat super für mich funktioniert; Am Ende habe ich es über in eine Reihe von Wörterbüchern für meine Bedürfnisse konvertiertDeserializeObject<Dictionary<string, object>[]>
.Am Ende habe ich eine Mischung aus beiden Antworten verwendet, da es keiner wirklich verstanden hat.
ToObject () kann die erste Eigenschaftsebene in einem JSON-Objekt ausführen, verschachtelte Objekte werden jedoch nicht in Dictionary () konvertiert.
Es ist auch nicht erforderlich, alles manuell zu erledigen, da ToObject () mit Eigenschaften der ersten Ebene ziemlich gut ist.
Hier ist der Code:
public static class JObjectExtensions { public static IDictionary<string, object> ToDictionary(this JObject @object) { var result = @object.ToObject<Dictionary<string, object>>(); var JObjectKeys = (from r in result let key = r.Key let value = r.Value where value.GetType() == typeof(JObject) select key).ToList(); var JArrayKeys = (from r in result let key = r.Key let value = r.Value where value.GetType() == typeof(JArray) select key).ToList(); JArrayKeys.ForEach(key => result[key] = ((JArray)result[key]).Values().Select(x => ((JValue)x).Value).ToArray()); JObjectKeys.ForEach(key => result[key] = ToDictionary(result[key] as JObject)); return result; } }
Es kann Randfälle geben, in denen es nicht funktioniert und die Leistung nicht die stärkste Qualität ist.
Danke Leute!
quelle
JObject
) selbst sind? Sie konvertieren sie nicht zuDictionary<string,object>
JObject
s auf.JArrays
könnten Elemente von seinJOBject
oderJArrray
, dann müssen diese in C # -Array und C # -Dictionary konvertiert werden , was der Code nicht tut.Hier ist die Anfangsversion : Ich habe den Code so geändert, dass JArrays und in JArrays / JObjects verschachtelte JObjects wieder verwendet werden , was in der akzeptierten Antwort nicht der Fall ist, wie von @Nawaz hervorgehoben.
using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; public static class JsonConversionExtensions { public static IDictionary<string, object> ToDictionary(this JObject json) { var propertyValuePairs = json.ToObject<Dictionary<string, object>>(); ProcessJObjectProperties(propertyValuePairs); ProcessJArrayProperties(propertyValuePairs); return propertyValuePairs; } private static void ProcessJObjectProperties(IDictionary<string, object> propertyValuePairs) { var objectPropertyNames = (from property in propertyValuePairs let propertyName = property.Key let value = property.Value where value is JObject select propertyName).ToList(); objectPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToDictionary((JObject) propertyValuePairs[propertyName])); } private static void ProcessJArrayProperties(IDictionary<string, object> propertyValuePairs) { var arrayPropertyNames = (from property in propertyValuePairs let propertyName = property.Key let value = property.Value where value is JArray select propertyName).ToList(); arrayPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToArray((JArray) propertyValuePairs[propertyName])); } public static object[] ToArray(this JArray array) { return array.ToObject<object[]>().Select(ProcessArrayEntry).ToArray(); } private static object ProcessArrayEntry(object value) { if (value is JObject) { return ToDictionary((JObject) value); } if (value is JArray) { return ToArray((JArray) value); } return value; } }
quelle
Klingt nach einem guten Anwendungsfall für Erweiterungsmethoden - ich hatte etwas herumliegen, das ziemlich einfach in Json.NET zu konvertieren war (Danke NuGet!):
Natürlich wird dies schnell zusammen gehackt - Sie möchten es aufräumen usw.
public static class JTokenExt { public static Dictionary<string, object> Bagify(this JToken obj, string name = null) { name = name ?? "obj"; if(obj is JObject) { var asBag = from prop in (obj as JObject).Properties() let propName = prop.Name let propValue = prop.Value is JValue ? new Dictionary<string,object>() { {prop.Name, prop.Value} } : prop.Value.Bagify(prop.Name) select new KeyValuePair<string, object>(propName, propValue); return asBag.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); } if(obj is JArray) { var vals = (obj as JArray).Values(); var alldicts = vals .SelectMany(val => val.Bagify(name)) .Select(x => x.Value) .ToArray(); return new Dictionary<string,object>() { {name, (object)alldicts} }; } if(obj is JValue) { return new Dictionary<string,object>() { {name, (obj as JValue)} }; } return new Dictionary<string,object>() { {name, null} }; } }
quelle
Hier ist eine einfachere Version:
public static object ToCollections(object o) { var jo = o as JObject; if (jo != null) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value)); var ja = o as JArray; if (ja != null) return ja.ToObject<List<object>>().Select(ToCollections).ToList(); return o; }
Wenn Sie C # 7 verwenden, können wir Pattern Matching verwenden, wo es so aussehen würde:
public static object ToCollections(object o) { if (o is JObject jo) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value)); if (o is JArray ja) return ja.ToObject<List<object>>().Select(ToCollections).ToList(); return o; }
quelle