将JSON对象层次结构反序列化为Dictionary <string,object =“”> </string,>的层次结构

时间:2012-11-29 17:19:28

标签: c# json windows-8

我在 .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);
}

这实际上适用于第一级,但是“Parent”只是一个无法转换为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”取决于请求)并且由于我的应用程序不是使用这些服务的唯一应用程序,我无法改变它,至少目前是这样。

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

这个系统适用于JSON.NET,但是如果服务器返回一个对象层次结构,子对象将作为JObjects存储在我的字典而不是另一个字典中。

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

2 个答案:

答案 0 :(得分:4)

我正在使用JSON.NET库和ExpandoObject类的组合在WinRT应用程序中解决同样的问题。该库能够很好地将JSON数据反序列化为实现IDictionary的ExpandoObjects。 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
            }
        }
    }
}

答案 1 :(得分:3)

试试这段代码片段:

var d = new System.Web.Script.Serialization.JavaScriptSerializer();
var results = d.Deserialize<Dictionary<string, object>>(jsonString);
var parent = (Dictionary<string, object>)results["Parent"];

根据参考资料,JavaScriptSerializer Class支持 Windows 8

对于反序列化,Json.NET也是 Windows 8 支持的选项。

已添加,适用于WinRT

  1. 根据您的JSON定义DataContract

    [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; }
    }
    
  2. 反序列化时使用DataContract类。

    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;
    }
    
  3. 参考:Creating .NET objects from JSON using DataContractJsonSerializer