【问题标题】:Deserializing a JSON object hierarchy into a hierarchy of Dictionary<string, object>将 JSON 对象层次结构反序列化为 Dictionary<string, object> 的层次结构
【发布时间】:2014-01-09 17:28:13
【问题描述】:

我在 .NET for WinRT (C#) 中,我想将 JSON 字符串反序列化为 Dictionary&lt;string, object&gt;,以后可以将字典值转换为实际类型。 JSON 字符串可以包含对象层次结构,我也希望在 Dictionary&lt;string, object&gt; 中有子对象。

这是它应该能够处理的示例 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&lt;string, object&gt; 的对象:

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&lt;string, JToken&gt;,这迫使我遍历整个层次结构并再次转换它们。

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

编辑

我正在使用Dictionary&lt;string, object&gt;,因为我的对象因服务器调用而异(例如,"Id" 属性可能是 "id"、*"cust_id "* 或 "customerId" 取决于请求),并且由于我的应用不是唯一使用这些服务的应用,因此我无法更改,至少目前是这样。

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

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

总而言之,我正在寻找一个高效的系统来使用 WinRT 中可用的 JSON 序列化程序将对象层次结构转换为 Dictionary&lt;string, object&gt; 的层次结构。

【问题讨论】:

  • 查看我编辑的答案。希望这会有所帮助!

标签: c# json windows-8


【解决方案1】:

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

【讨论】:

  • 非常有趣,看起来像我要找的东西。我今天会试一试,看看它是否合适(功能和性能方面)!
【解决方案2】:

试试这段代码sn-p:

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

参考:Creating .NET objects from JSON using DataContractJsonSerializer

【讨论】:

  • 请注意,该类型包含在 System.Web.Extensions 程序集中。它可用于 WinRT 应用程序吗?
  • 嗯,它没有出现在支持的 API 列表中msdn.microsoft.com/en-us/library/windows/apps/br230232.aspx
  • .NET 在 Windows 8 主机上运行!= WinRT .NET 应用程序。
  • 谢谢,但 System.Web 命名空间在 WinRT 的 .NET 中不可用。关于第二个解决方案,它在这种情况下适用,因为层次结构的所有对象都是相同的,但在我的实际应用程序中并非总是如此(因此使用 Dictionary btw)。
猜你喜欢
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 2016-07-13
  • 2017-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多