我在 .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>
的层次结构。
答案 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
:
根据您的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; }
}
反序列化时使用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