我在 .NET for WinRT(C#)中 ,我想将JSON字符串反序列化为Dictionary<string, object>,然后将字典值稍后转换为实际类型。JSON字符串可以包含对象层次结构,我也希望在其中包含子对象Dictionary<string, object>。
Dictionary<string, object>
这是应该能够处理的示例JSON:
{ "Name":"John Smith", "Age":42, "Parent": { "Name":"Brian Smith", "Age":65, "Parent": { "Name":"James Smith", "Age":87, } } }
我尝试使用 DataContractJsonSerializer 这样做:
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); }
实际上,这对于第一个级别是可行的,但是 “父母” 只是一个不能强制转换为的对象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>'
然后,我尝试使用 Json.NET, 但子对象本身就是JObject IDictionary<string, JToken>,这迫使我遍历整个层次结构并将其再次转换。
IDictionary<string, JToken>
有人知道如何使用现有的序列化程序解决此问题吗?
编辑
我Dictionary<string, object>之所以使用,是因为我的对象从一个服务器调用到另一个服务器调用(例如, “ Id” 属性可能是 “ id” ,“ cust_id” 或 “ customerId”, 具体取决于请求),而我的应用程序不是唯一的使用这些服务的应用程序,至少到目前为止,我无法更改它。
因此,我发现在这种情况下使用 DataContractAttribute 和 DataMemberAttribute 不方便。相反,我想将所有内容存储在通用字典中,并具有一个强类型属性“ Id”,该属性在字典中查找“ id”,“ cust_id”或“ customerId”,从而使其对UI透明。
该系统可与JSON.NET完美配合,但是,如果服务器返回对象层次结构,则子对象将作为JObjects存储在我的字典中,而不是另一个字典中。
综上所述,我正在寻找一种有效的系统,以Dictionary<string, object>使用WinRT中提供的JSON序列化程序将对象层次结构转换为层次结构。
我正在使用JSON.NET库和ExpandoObject类的组合解决WinRT应用程序中的同一问题。该库能够将JSON数据很好地反序列化为ExpandoObjects,后者实现IDictionary。ExpandoObject的键/值对的值可以轻松地视为另一个ExpandoObject。
这是我使用的适合您的样本的方法:
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 } } } }