将JSON对象层次结构反序列化为Dictionary< string,object>层次结构 [英] Deserializing a JSON object hierarchy into a hierarchy of Dictionary<string, object>

查看:188
本文介绍了将JSON对象层次结构反序列化为Dictionary< string,object>层次结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 .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 ,但是子对象本身就是IDictionary<string, JToken>,这迫使我遍历整个层次结构并将其再次转换.

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

编辑

我之所以使用Dictionary<string, object>,是因为我的对象从一个服务器调用到另一个服务器调用有所不同(例如,"Id" 属性可能是"id" ,*"cust_id "*或" customerId"(取决于请求)),由于我的应用不是唯一使用这些服务的应用,因此至少在目前,我无法更改它.

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

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

总而言之,我正在寻找一个有效的系统,使用WinRT中提供的JSON序列化程序将对象层次结构转换为Dictionary<string, object>层次结构.

解决方案

我正在结合使用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
            }
        }
    }
}

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.

解决方案

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
            }
        }
    }
}

这篇关于将JSON对象层次结构反序列化为Dictionary&lt; string,object&gt;层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆