小编典典

将JSON对象层次结构反序列化为Dictionary层次结构

json

我在 .NET for WinRT(C#)中 ,我想将JSON字符串反序列化为Dictionary<string, object>,然后将字典值稍后转换为实际类型。JSON字符串可以包含对象层次结构,我也希望在其中包含子对象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>,这迫使我遍历整个层次结构并将其再次转换。

有人知道如何使用现有的序列化程序解决此问题吗?

编辑

Dictionary<string, object>之所以使用,是因为我的对象从一个服务器调用到另一个服务器调用(例如, “ Id” 属性可能是
“ id”“ cust_id” “ customerId”,
具体取决于请求),而我的应用程序不是唯一的使用这些服务的应用程序,至少到目前为止,我无法更改它。

因此,我发现在这种情况下使用 DataContractAttributeDataMemberAttribute
不方便。相反,我想将所有内容存储在通用字典中,并具有一个强类型属性“ Id”,该属性在字典中查找“ id”,“ cust_id”或“
customerId”,从而使其对UI透明。

该系统可与JSON.NET完美配合,但是,如果服务器返回对象层次结构,则子对象将作为JObjects存储在我的字典中,而不是另一个字典中。

综上所述,我正在寻找一种有效的系统,以Dictionary<string, object>使用WinRT中提供的JSON序列化程序将对象层次结构转换为层次结构。


阅读 410

收藏
2020-07-27

共1个答案

小编典典

我正在使用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
            }
        }
    }
}
2020-07-27