问题
I'm in .NET for WinRT (C#) and I'd like to deserialize a JSON string to a Dictionary<string, object>
, where the dictionary value can later be converted to the actual type.
The JSON string can contain an object hierarchy and I'd like to have child objects in Dictionary<string, object>
as well.
Here's a sample JSON it should be able to handle:
{
"Name":"John Smith",
"Age":42,
"Parent":
{
"Name":"Brian Smith",
"Age":65,
"Parent":
{
"Name":"James Smith",
"Age":87,
}
}
}
I tried with the DataContractJsonSerializer doing as so:
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Dictionary<string, object>), settings);
Dictionary<string, object> results = (Dictionary<string, object>)serializer.ReadObject(ms);
}
This actually works fine for the first level, but then "Parent" is just an object which cannot be casted to a Dictionary<string, object>
:
Dictionary<string, object> parent = (Dictionary<string, object>)results["Parent"];
Cannot cast 'results["Parent"]' (which has an actual type of 'object') to 'System.Collections.Generic.Dictionary<string,object>'
I then tried using Json.NET but child objects are JObject themselves being IDictionary<string, JToken>
, which forces me to iterate through the full hierarchy and convert them over again.
Would someone know how to solve this problem using an existing serializer?
EDIT
I'm using Dictionary<string, object>
because my objects vary from one server call to another (e.g. the "Id" property might be "id", *"cust_id"* or "customerId" depending on the request) and as my app isn't the only app using those services, I can't change that, at least for now.
Therefore, I found it inconvenient to use DataContractAttribute and DataMemberAttribute in this situation. Instead I'd like to store everything in a generic dictionary, and have a single strongly-typed property "Id" which looks for "id", "cust_id" or "customerId" in the dictionary making it transparent for the UI.
This system works great with JSON.NET, however if ever the server returns an object hierarchy, sub-objects will be stored as JObjects in my dictionary instead of another dictionary.
To sum-up, I'm looking for an efficient system to transform an object hierarchy into a hierarchy of Dictionary<string, object>
using a JSON serializer available in WinRT.
回答1:
I'm addressing this same issue in a WinRT app using a combination of the JSON.NET library and the ExpandoObject class. The library is able to deserialize JSON data quite nicely into ExpandoObjects, which implement IDictionary. The value of an ExpandoObject's key-value pair may easily be treated as another ExpandoObject.
Here's the approach I used, adapted to your sample:
void LoadJSONData()
{
string testData = "{ \"Name\":\"John Smith\", \"Age\":42, \"Parent\": { \"Name\":\"Brian Smith\", \"Age\":65, \"Parent\": { \"Name\":\"James Smith\", \"Age\":87, } } }";
ExpandoObject dataObj = JsonConvert.DeserializeObject<ExpandoObject>(testData, new ExpandoObjectConverter());
// Grab the parent object directly (if it exists) and treat as ExpandoObject
var parentElement = dataObj.Where(el => el.Key == "Parent").FirstOrDefault();
if (parentElement.Value != null && parentElement.Value is ExpandoObject)
{
ExpandoObject parentObj = (ExpandoObject)parentElement.Value;
// do something with the parent object...
}
// Alternately, iterate through the properties of the expando
foreach (var property in (IDictionary<String, Object>)dataObj)
{
if (property.Key == "Parent" && property.Value != null && property.Value is ExpandoObject)
{
foreach (var parentProp in (ExpandoObject)property.Value)
{
// do something with the properties in the parent expando
}
}
}
}
回答2:
Try this piece of code snippet:
var d = new System.Web.Script.Serialization.JavaScriptSerializer();
var results = d.Deserialize<Dictionary<string, object>>(jsonString);
var parent = (Dictionary<string, object>)results["Parent"];
According to the reference, JavaScriptSerializer Class supports Windows 8.
For deserialization, Json.NET is also an option to be considered with Windows 8 support.
ADDED, For WinRT
:
Define the
DataContract
according to your JSON.[DataContract] public class CustomObject { [DataMember(Name = "Name")] public string Name { get; set; } [DataMember(Name = "Age")] public string Age { get; set; } [DataMember(Name = "Parent")] public Dictionary<string, object> Parent { get; set; } }
Use the
DataContract
class while deserialization.using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) { DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings(); settings.UseSimpleDictionaryFormat = true; DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CustomObject), settings); CustomObject results = (CustomObject)serializer.ReadObject(ms); Dictionary<string, object> parent = results.Parent; }
Reference: Creating .NET objects from JSON using DataContractJsonSerializer
来源:https://stackoverflow.com/questions/13631208/deserializing-a-json-object-hierarchy-into-a-hierarchy-of-dictionarystring-obj